| // Generated by CoffeeScript 1.9.3 |
| var API, APIVERSION, Chart, HTML, Row, WarbleLogin, WarbleLoginCallback, Widget, aSourceTypes, addSourceType, addSources, addorguser, addsources, affiliate, affiliation, affiliationWizard, altemail, app, badModal, bio, chartOnclick, chartToSvg, chartWrapperButtons, charts_donutchart, charts_gaugechart, charts_linechart, charts_linechart_stacked, charts_linked, charts_radarchart, ciexplorer, clientTypes, clientlist, cog, comShow, comstat, copyCSS, currentSources, dataTable, datepicker, datepickers, defaultOrgChanged, deleteNode, deletesource, doResetPass, donut, downloadBlob, explorer, fScreen, factors, fetch, fetchPhonebook, filterPerson, filterView, findWidget, forumexplorer, gauge, genColors, get, getResetToken, getSourceType, globArgs, hsl2rgb, imexplorer, inviteMember, isArray, isHash, issueexplorer, jsondump, keyValueForm, linechart, loadPageWidgets, logexplorer, login, mailexplorer, make5, makeClientType, makeOrg, manageviews, memberInvited, membershipList, messages, mk, modifyNode, multiviewexplorer, mvp, newview, nodeStatusSort, nodeVal, orgCreated, orgadmin, orglist, pageID, paragraph, patch, phonebook_cached, post, postPublishLink, preferences, pubWidget, publishWidget, publisher, publisherPublic, publisherWidget, put, pwReset, quickColors, radar, radarIndicators, rcollate, redirs, relationship, remail, remorguser, removeMember, renderAccountInfo, renderPhonebook, report, resetpw, rmview, rotateTable, rowZ, saveNodeValue, savedNodeValue, saveprefs, saveview, sendEmail, set, setDefaultOrg, setupPage, setupPhonebook, showClientType, showMore, showType, signout, signup, snap, sourceAdded, sourceTypes, sourceadd, sourceexplorer, sourcelist, sourceret, st, stackChart, subFilter, subFilterGlob, swi, switchChartType, tagList, theme, toFullscreen, toNormal, top5, treemap, trend, trendBox, txt, updateTimeseriesWidgets, updateWidgets, userAccount, validateLogin, validateSignup, viewJS, viewexplorer, widgetCache, widgetexplorer, worldmap, xdelete, xxCharts, |
| indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; |
| |
| signup = function(form) { |
| var err; |
| err = null; |
| if (form.name.value.length < 2) { |
| err = "Please enter your full name"; |
| } else if (form.screenname.value.length < 1) { |
| err = "Please enter a screen name"; |
| } else if (form.email.value.length < 6 || !form.email.value.match(/^[^\r\n\s @]+@[^\r\n\s @]+$/)) { |
| err = "Please enter a valid email address"; |
| } else if (form.password.value.length < 1 || form.password.value !== form.password2.value) { |
| err = "Please enter your password and make sure it matches the re-type"; |
| } |
| if (err) { |
| document.getElementById('signupmsg').innerHTML = "<h2>Error: " + err + "</h2>"; |
| return false; |
| } else { |
| document.getElementById('signupmsg').innerHTML = "Creating account, hang on..!"; |
| post('user-signup', { |
| action: 'create', |
| name: form.name.value, |
| password: form.password.value, |
| screenname: form.screenname.value, |
| email: form.email.value, |
| code: form.code.value |
| }, null, validateSignup); |
| return false; |
| } |
| }; |
| |
| validateSignup = function(json, state) { |
| if (json.created) { |
| return document.getElementById('signupmsg').innerHTML = "<span style='color: #060;'>Account created! Please check your inbox for verification instructions.</span>"; |
| } else { |
| return document.getElementById('signupmsg').innerHTML = "<h2 style='font-size: 2rem; color: #830;'>Error: " + json.message + "</h2>"; |
| } |
| }; |
| |
| login = function(form) { |
| if (form.username.value.length > 5 && form.password.value.length > 0) { |
| cog(document.getElementById('loginmsg')); |
| post('account', { |
| username: form.username.value, |
| password: form.password.value, |
| api: form.api.value |
| }, null, validateLogin); |
| } |
| return false; |
| }; |
| |
| validateLogin = function(json, state) { |
| if (json.loginRequired) { |
| return document.getElementById('loginmsg').innerHTML = json.error; |
| } else { |
| if (json.apiversion && json.apiversion >= 3) { |
| if (document.referrer && document.referrer.match(/https:\/\/(?:www)?\.snoot\.io\/dashboard/i)) { |
| return location.href = document.referrer; |
| } else { |
| return location.href = "/dashboard.html?page=default"; |
| } |
| } else { |
| return location.href = "/api2.html?page=default"; |
| } |
| } |
| }; |
| |
| doResetPass = function() { |
| var newpass, rtoken; |
| rtoken = get('rtoken').value; |
| newpass = get('newpass').value; |
| post('account', { |
| remail: remail, |
| rtoken: rtoken, |
| newpass: newpass |
| }, null, pwReset); |
| return false; |
| }; |
| |
| remail = ""; |
| |
| pwReset = function() { |
| return get('resetform').innerHTML = "Assuming you entered the right token, your password has now been reset!. <a href='login.html'>Log in</a>."; |
| }; |
| |
| getResetToken = function(json, state) { |
| var btn, form, newpw, p, token; |
| form = get('resetform'); |
| form.innerHTML = ""; |
| p = mk('p', {}, "A reset token has been sent to your email address. Please enter the reset token and your new preferred password below:"); |
| app(form, p); |
| token = mk('input', { |
| type: 'text', |
| placeholder: 'Reset token', |
| autocomplete: 'off', |
| name: 'rtoken', |
| id: 'rtoken' |
| }); |
| newpw = mk('input', { |
| type: 'password', |
| placeholder: 'New passord', |
| autocomplete: 'off', |
| name: 'newpass', |
| id: 'newpass' |
| }); |
| app(form, token); |
| app(form, mk('br')); |
| app(form, newpw); |
| app(form, mk('br')); |
| btn = mk('input', { |
| type: 'button', |
| onclick: 'doResetPass()', |
| value: 'Reset your password' |
| }); |
| form.setAttribute("onsubmit", "return doResetPass();"); |
| return app(form, btn); |
| }; |
| |
| resetpw = function() { |
| var email; |
| email = get('email').value; |
| remail = email; |
| post('account', { |
| reset: email |
| }, null, getResetToken); |
| return false; |
| }; |
| |
| charts_donutchart = function(obj, data, maxN) { |
| var a, asDataArray, c, config, el, k, len, narr, others, q, v; |
| a = 0; |
| asDataArray = []; |
| if (data.counts) { |
| data = data.counts; |
| } |
| for (k in data) { |
| v = data[k]; |
| asDataArray.push([k, v]); |
| a++; |
| } |
| asDataArray.sort((function(_this) { |
| return function(a, b) { |
| return b[1] - a[1]; |
| }; |
| })(this)); |
| if (maxN && asDataArray.length > maxN) { |
| others = 0; |
| narr = asDataArray.slice(maxN, asDataArray.length - maxN); |
| asDataArray = asDataArray.slice(0, maxN); |
| for (q = 0, len = narr.length; q < len; q++) { |
| el = narr[q]; |
| others += el[1]; |
| } |
| asDataArray.push(['Others', others]); |
| asDataArray.sort((function(_this) { |
| return function(a, b) { |
| return b[1] - a[1]; |
| }; |
| })(this)); |
| } |
| config = { |
| bindto: obj, |
| data: { |
| columns: asDataArray, |
| type: 'donut' |
| }, |
| donut: { |
| width: 50 |
| }, |
| color: { |
| pattern: genColors(a + 1, 0.55, 0.475, true) |
| }, |
| tooltip: { |
| format: { |
| value: (function(_this) { |
| return function(val) { |
| return d3.format(',')(val); |
| }; |
| })(this) |
| } |
| } |
| }; |
| c = c3.generate(config); |
| return [c, config]; |
| }; |
| |
| charts_gaugechart = function(obj, data) { |
| var c, config; |
| if (data.gauge) { |
| data = data.gauge; |
| } |
| config = { |
| bindto: obj, |
| data: { |
| columns: [[data.key || 'value', data.value || data]], |
| type: 'gauge' |
| }, |
| gauge: { |
| min: 0, |
| max: 100 |
| }, |
| color: { |
| pattern: ['#FF0000', '#F97600', '#F6C600', '#60B044'], |
| threshold: { |
| values: [25, 55, 80, 100] |
| } |
| }, |
| tooltip: { |
| format: { |
| value: (function(_this) { |
| return function(val) { |
| return d3.format(',')(val); |
| }; |
| })(this) |
| } |
| } |
| }; |
| c = c3.generate(config); |
| return [c, config]; |
| }; |
| |
| gauge = function(json, state) { |
| var gaugeChart, lmain; |
| lmain = new HTML('div'); |
| state.widget.inject(lmain, true); |
| if (json.gauge && json.gauge.text) { |
| lmain.inject(new HTML('p', {}, json.gauge.text)); |
| } |
| return gaugeChart = new Chart(lmain, 'gauge', json); |
| }; |
| |
| charts_linechart_stacked = (function(_this) { |
| return function(o, d) { |
| return charts_linechart(o, d, 'area-spline', true); |
| }; |
| })(this); |
| |
| charts_linechart = function(obj, data, options) { |
| var a, aa, asDataArray, asList, asTypes, axisData, c, config, dataPoint, dateFormat, el, k, key, len, len1, len2, linetype, ndate, q, ref, ref1, stacked, tmpArray, ts, u, v, val, xts, xx; |
| linetype = options && options.linetype ? options.linetype : 'line'; |
| stacked = options && options.stacked ? options.stacked : false; |
| if (options && options.filled && linetype === "line") { |
| linetype = "area-spline"; |
| } |
| a = 0; |
| asDataArray = []; |
| asList = []; |
| asTypes = []; |
| axisData = { |
| y: { |
| tick: { |
| format: d3.format('s') |
| } |
| } |
| }; |
| if (data.timeseries && isArray(data.timeseries)) { |
| dateFormat = '%Y-%m-%d'; |
| if (data.histogram && data.histogram === 'quarterly') { |
| dateFormat = (function(_this) { |
| return function(x) { |
| return "Q" + [1, 2, 3, 4][Math.floor(x.getMonth() / 3)] + ", " + x.getFullYear(); |
| }; |
| })(this); |
| } |
| if (data.histogram && data.histogram === 'monthly') { |
| dateFormat = '%b, %Y'; |
| } |
| if (data.interval && data.interval === 'hour') { |
| dateFormat = '%Y-%m-%d %H:%M'; |
| } |
| if (data.histogram && data.histogram === 'yearly') { |
| dateFormat = '%Y'; |
| } |
| ts = [['x']]; |
| xts = {}; |
| ref = data.timeseries; |
| for (q = 0, len = ref.length; q < len; q++) { |
| el = ref[q]; |
| axisData.x = { |
| type: 'timeseries', |
| tick: { |
| format: dateFormat |
| } |
| }; |
| ndate = new Date(parseInt(el.date) * 1000.0); |
| ts[0].push(ndate); |
| for (k in el) { |
| v = el[k]; |
| if (k !== 'date') { |
| if (k === 'deletions') { |
| v = -v; |
| } |
| if (xts[k] === void 0) { |
| xts[k] = []; |
| } |
| xts[k].push(v); |
| } |
| } |
| } |
| for (key in xts) { |
| val = xts[key]; |
| xx = [key]; |
| for (u = 0, len1 = val.length; u < len1; u++) { |
| el = val[u]; |
| xx.push(el); |
| } |
| ts.push(xx); |
| asList.push(key); |
| asTypes[key] = linetype; |
| a++; |
| } |
| asDataArray = ts; |
| } else { |
| ref1 = data.counts; |
| for (k in ref1) { |
| v = ref1[k]; |
| asList.push(k); |
| asTypes[k] = 'bar'; |
| tmpArray = [k]; |
| if (isArray(v)) { |
| for (aa = 0, len2 = v.length; aa < len2; aa++) { |
| dataPoint = v[aa]; |
| tmpArray.push(dataPoint); |
| } |
| } else { |
| tmpArray.push(v); |
| } |
| asDataArray.push(tmpArray); |
| a++; |
| } |
| } |
| config = { |
| bindto: obj, |
| data: { |
| x: data.timeseries ? 'x' : null, |
| columns: asDataArray, |
| types: asTypes, |
| groups: stacked ? [asList] : [[]] |
| }, |
| axis: axisData, |
| color: { |
| pattern: genColors(a + 1, 0.55, 0.475, true) |
| }, |
| subchart: { |
| show: false |
| }, |
| point: { |
| show: false |
| }, |
| bar: { |
| width: { |
| ratio: 0.7 |
| } |
| }, |
| tooltip: { |
| format: { |
| value: (function(_this) { |
| return function(val) { |
| return d3.format(',')(val); |
| }; |
| })(this) |
| } |
| } |
| }; |
| c = c3.generate(config); |
| return [c, config]; |
| }; |
| |
| charts_linked = function(obj, nodes, links, options) { |
| var avg, bb, defs, edges, force, g, gatherTargets, lTargets, lcolors, licolors, link, linked_zoom, lla, llcolors, llheight, llwidth, node, svg, tooltip, uptop, x; |
| llcolors = genColors(nodes.length + 1, 0.55, 0.475, true); |
| licolors = genColors(nodes.length + 1, 0.375, 0.35, true); |
| lla = 0; |
| obj.className = "chartChart linkedChart"; |
| svg = d3.select(obj).append("svg").attr("width", "100%").attr("height", "600"); |
| g = svg.append("g"); |
| bb = obj.getBoundingClientRect(); |
| llwidth = bb.width; |
| llheight = Math.max(600, bb.height); |
| tooltip = d3.select("body").append("div").attr("class", "link_tooltip").style("opacity", 0); |
| avg = links.length / nodes.length; |
| force = d3.layout.force().gravity(0.015).distance(llheight / 8).charge(-200 / Math.log10(nodes.length)).linkStrength(0.2 / avg).size([llwidth, llheight]); |
| edges = []; |
| links.forEach(function(e) { |
| var sourceNode, targetNode; |
| sourceNode = nodes.filter((function(_this) { |
| return function(n) { |
| return n.id === e.source; |
| }; |
| })(this))[0]; |
| targetNode = nodes.filter((function(_this) { |
| return function(n) { |
| return n.id === e.target; |
| }; |
| })(this))[0]; |
| return edges.push({ |
| source: sourceNode, |
| target: targetNode, |
| s: e.source, |
| value: e.value, |
| name: e.name, |
| tooltip: e.tooltip |
| }); |
| }); |
| force.nodes(nodes).links(edges).start(); |
| lcolors = {}; |
| nodes.forEach(function(e) { |
| return lcolors[e.id] = licolors[lla++]; |
| }); |
| lla = 0; |
| link = g.selectAll(".link").data(edges).enter().append("path").attr("class", "link_link").attr("id", (function(_this) { |
| return function(d) { |
| return d.name; |
| }; |
| })(this)).attr("data-source", (function(_this) { |
| return function(d) { |
| return d.source.id; |
| }; |
| })(this)).attr("data-target", (function(_this) { |
| return function(d) { |
| return d.target.id; |
| }; |
| })(this)).attr("style", (function(_this) { |
| return function(d) { |
| return "stroke-width: " + d.value + "; stroke: " + lcolors[d.s] + ";"; |
| }; |
| })(this)).on("mouseover", function(d) { |
| if (d.tooltip) { |
| tooltip.transition().duration(100).style("opacity", .9); |
| return tooltip.html(("<b>" + d.name + ":</b><br/>") + d.tooltip.replace("\n", "<br/>")).style("left", (d3.event.pageX + 20) + "px").style("top", (d3.event.pageY - 28) + "px"); |
| } |
| }).on("mouseout", function(d) { |
| d3.select(this).style("stroke-opacity", "0.375"); |
| return tooltip.transition().duration(200).style("opacity", 0); |
| }); |
| defs = svg.append("defs"); |
| nodes.forEach(function(n) { |
| if (n.gravatar) { |
| return defs.append("pattern").attr("id", "gravatar-" + n.id).attr("patternUnits", "userSpaceOnUse").attr("width", n.size * 2).attr("height", n.size * 2).attr("x", n.size).attr("y", n.size).append("image").attr("width", n.size * 2).attr("height", n.size * 2).attr("x", "0").attr("y", "0").attr("xlink:href", "https://secure.gravatar.com/avatar/" + n.gravatar + ".png?d=identicon"); |
| } else { |
| return n.gravatar = false; |
| } |
| }); |
| node = g.selectAll(".node").data(nodes).enter().append("g").attr("class", "link_node").attr("data-source", (function(_this) { |
| return function(d) { |
| return d.id; |
| }; |
| })(this)).call(force.drag); |
| lTargets = []; |
| gatherTargets = function(d, e) { |
| if (e.source === d || e.target === d) { |
| lTargets.push(e.source.id); |
| lTargets.push(e.target.id); |
| return true; |
| } |
| return false; |
| }; |
| uptop = svg.append("g"); |
| x = null; |
| node.append("circle").attr("class", "link_node").attr("data-source", (function(_this) { |
| return function(d) { |
| return d.id; |
| }; |
| })(this)).attr("data-color", (function(_this) { |
| return function(d) { |
| lla++; |
| return llcolors[lla - 1]; |
| }; |
| })(this)).style("fill", function(d) { |
| if (d.gravatar) { |
| return "url(#gravatar-" + d.id + ")"; |
| } else { |
| return "" + (d3.select(this).attr('data-color')); |
| } |
| }).style("stroke", "black").attr("r", (function(_this) { |
| return function(d) { |
| return d.size; |
| }; |
| })(this)).on("mouseover", function(d) { |
| lTargets.push(d.id); |
| d3.selectAll("path").style("stroke-opacity", "0.075"); |
| d3.selectAll("path").filter((function(_this) { |
| return function(e) { |
| return gatherTargets(d, e); |
| }; |
| })(this)).style("stroke-opacity", "1").style("z-index", "20"); |
| d3.selectAll("path").filter((function(_this) { |
| return function(e) { |
| return e.source === d || e.target; |
| }; |
| })(this)).each((function(_this) { |
| return function(o) { |
| x = d3.select(_this).insert("g", ":first-child").style("stroke", "red !important"); |
| return x.append("use").attr("xlink:href", "#" + o.name); |
| }; |
| })(this)); |
| d3.selectAll("circle").filter((function(_this) { |
| return function(e) { |
| var ref; |
| return ref = e.id, indexOf.call(lTargets, ref) < 0; |
| }; |
| })(this)).style("opacity", "0.2"); |
| return d3.selectAll("text").filter((function(_this) { |
| return function(e) { |
| var ref; |
| return ref = e.id, indexOf.call(lTargets, ref) < 0; |
| }; |
| })(this)).style("opacity", "0.2"); |
| }).on("mouseout", function(d) { |
| lTargets = []; |
| if (x) { |
| x.selectAll("*").remove(); |
| } |
| d3.selectAll("circle").style("opacity", null); |
| d3.selectAll("text").style("opacity", null); |
| return d3.selectAll("path").style("stroke-opacity", null); |
| }); |
| node.append("a").attr("href", (function(_this) { |
| return function(d) { |
| if (!d.gravatar) { |
| return "#"; |
| } else { |
| return "contributors.html?page=biography&email=" + d.id; |
| } |
| }; |
| })(this)).append("text").attr("dx", 13).attr("dy", ".35em").text((function(_this) { |
| return function(d) { |
| return d.name; |
| }; |
| })(this)).on("mouseover", function(d) { |
| if (d.tooltip) { |
| tooltip.transition().duration(100).style("opacity", .9); |
| return tooltip.html(("<b>" + d.name + ":</b><br/>") + d.tooltip.replace("\n", "<br/>")).style("left", (d3.event.pageX + 20) + "px").style("top", (d3.event.pageY - 28) + "px"); |
| } |
| }).on("mouseout", function(d) { |
| return tooltip.transition().duration(200).style("opacity", 0); |
| }); |
| force.on("tick", function() { |
| link.attr("d", function(d) { |
| var dr, dx, dy; |
| dx = d.target.x - d.source.x; |
| dy = d.target.y - d.source.y; |
| dr = Math.sqrt(dx * dx + dy * dy); |
| return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y; |
| }); |
| node.attr("cx", (function(_this) { |
| return function(d) { |
| return d.x = Math.max(d.size, Math.min(llwidth - d.size, d.x)); |
| }; |
| })(this)).attr("cy", (function(_this) { |
| return function(d) { |
| return d.y = Math.max(d.size, Math.min(llheight - d.size, d.y)); |
| }; |
| })(this)); |
| return node.attr("transform", (function(_this) { |
| return function(d) { |
| return "translate(" + d.x + "," + d.y + ")"; |
| }; |
| })(this)); |
| }); |
| linked_zoom = function() { |
| var isShift; |
| isShift = !!window.event.shiftKey; |
| if (isShift) { |
| return g.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")"); |
| } else { |
| return g.attr("transform", "scale(" + d3.event.scale + ")"); |
| } |
| }; |
| svg.call(d3.behavior.zoom().center([llwidth / 2, llheight / 2]).scaleExtent([0.333, 4]).on("zoom", linked_zoom)); |
| return [ |
| { |
| svg: svg, |
| parent: obj, |
| force: force, |
| config: {}, |
| resize: function(conf) { |
| var ns; |
| ns = ""; |
| if (conf.height) { |
| ns += "height: " + conf.height + "px; "; |
| } |
| if (conf.width) { |
| ns += "width: " + conf.width + "px; "; |
| } |
| svg.attr("style", ns); |
| llwidth = parseInt(svg.style("width")); |
| llheight = parseInt(svg.style("height")); |
| force.size([llwidth, llheight]).distance(llheight / 4); |
| return force.nodes(nodes).links(edges).start(); |
| } |
| }, { |
| linked: true |
| } |
| ]; |
| }; |
| |
| charts_radarchart = function(obj, data, options) { |
| var Format, LegendOptions, aa, ab, axes, axis, cfg, d, el, g, i, indicator, j, legend, len, len1, levelFactor, li, q, radius, rect, ref, ref1, ref2, ref3, series, tooltip, total, u; |
| cfg = { |
| radius: 5, |
| w: 360, |
| h: 360, |
| factor: 1, |
| factorLegend: .85, |
| levels: 4, |
| maxValue: 100, |
| radians: 2 * Math.PI, |
| opacityArea: 0.5, |
| ToRight: 5, |
| TranslateX: 30, |
| TranslateY: 30, |
| ExtraWidthX: 200, |
| ExtraWidthY: 100, |
| color: genColors(16, 0.55, 0.475, true) |
| }; |
| LegendOptions = []; |
| d = data; |
| if (data.indicators && data.data) { |
| d = []; |
| ref = data.data; |
| for (i = q = 0, len = ref.length; q < len; i = ++q) { |
| el = ref[i]; |
| li = []; |
| LegendOptions.push(el.name); |
| ref1 = data.indicators; |
| for (j = u = 0, len1 = ref1.length; u < len1; j = ++u) { |
| indicator = ref1[j]; |
| li.push({ |
| axis: indicator, |
| value: el.value[j] |
| }); |
| } |
| d.push(li); |
| } |
| } |
| cfg.maxValue = Math.max(cfg.maxValue, d3.max(d, (function(_this) { |
| return function(i) { |
| return d3.max(i.map(function(o) { |
| return o.value; |
| })); |
| }; |
| })(this))); |
| axes = d[0].map((function(_this) { |
| return function(i, j) { |
| return i.axis; |
| }; |
| })(this)); |
| total = axes.length; |
| radius = cfg.factor * Math.min(cfg.w / 2, cfg.h / 2); |
| Format = (function(_this) { |
| return function(edge) { |
| return Math.floor((edge / 24) + 0.5) + "↑ (" + (Math.pow(5, edge / 24)).pretty() + ")"; |
| }; |
| })(this); |
| d3.select(obj).select("svg").remove(); |
| rect = obj.getBoundingClientRect(); |
| g = d3.select(obj).append("svg").attr("preserveAspectRatio", "xMinYMin meet").attr("viewBox", "0 0 1000 500").append("g").attr("transform", "translate(" + cfg.TranslateX + "," + cfg.TranslateY + ")"); |
| for (j = aa = 0, ref2 = cfg.levels; 0 <= ref2 ? aa < ref2 : aa > ref2; j = 0 <= ref2 ? ++aa : --aa) { |
| levelFactor = cfg.factor * radius * ((j + 1) / cfg.levels); |
| g.selectAll(".levels").data(axes).enter().append("svg:line").attr("x1", (function(_this) { |
| return function(d, i) { |
| return levelFactor * (1 - cfg.factor * Math.sin(i * cfg.radians / total)); |
| }; |
| })(this)).attr("y1", (function(_this) { |
| return function(d, i) { |
| return levelFactor * (1 - cfg.factor * Math.cos(i * cfg.radians / total)); |
| }; |
| })(this)).attr("x2", (function(_this) { |
| return function(d, i) { |
| return levelFactor * (1 - cfg.factor * Math.sin((i + 1) * cfg.radians / total)); |
| }; |
| })(this)).attr("y2", (function(_this) { |
| return function(d, i) { |
| return levelFactor * (1 - cfg.factor * Math.cos((i + 1) * cfg.radians / total)); |
| }; |
| })(this)).attr("class", "line").style("stroke", "grey").style("stroke-opacity", "0.75").style("stroke-width", "0.3px").attr("transform", "translate(" + (cfg.w / 2 - levelFactor) + ", " + (cfg.h / 2 - levelFactor) + ")"); |
| } |
| for (j = ab = 0, ref3 = cfg.levels; 0 <= ref3 ? ab < ref3 : ab > ref3; j = 0 <= ref3 ? ++ab : --ab) { |
| levelFactor = cfg.factor * radius * ((j + 1) / cfg.levels); |
| g.selectAll(".levels").data([1]).enter().append("svg:text").attr("x", (function(_this) { |
| return function(d) { |
| return levelFactor * (1 - cfg.factor * Math.sin(0)); |
| }; |
| })(this)).attr("y", (function(_this) { |
| return function(d) { |
| return levelFactor * (1 - cfg.factor * Math.cos(0)); |
| }; |
| })(this)).attr("class", "legend").style("font-family", "sans-serif").style("font-size", "10px").attr("transform", "translate(" + (cfg.w / 2 - levelFactor + cfg.ToRight) + ", " + (cfg.h / 2 - levelFactor) + ")").attr("fill", "#737373").text(Format((j + 1) * cfg.maxValue / cfg.levels)); |
| } |
| series = 0; |
| axis = g.selectAll(".axis").data(axes).enter().append("g").attr("class", "axis"); |
| axis.append("line").attr("x1", cfg.w / 2).attr("y1", cfg.h / 2).attr("x2", (function(_this) { |
| return function(d, i) { |
| return cfg.w / 2 * (1 - cfg.factor * Math.sin(i * cfg.radians / total)); |
| }; |
| })(this)).attr("y2", (function(_this) { |
| return function(d, i) { |
| return cfg.h / 2 * (1 - cfg.factor * Math.cos(i * cfg.radians / total)); |
| }; |
| })(this)).attr("class", "line").style("stroke", "grey").style("stroke-width", "1px"); |
| axis.append("text").attr("class", "legend").text((function(_this) { |
| return function(d) { |
| return d; |
| }; |
| })(this)).style("font-family", "sans-serif").style("font-size", "11px").attr("text-anchor", "middle").attr("dy", "1.5em").attr("transform", (function(_this) { |
| return function(d, i) { |
| return "translate(0, -10)"; |
| }; |
| })(this)).attr("x", (function(_this) { |
| return function(d, i) { |
| return cfg.w / 2 * (1 - cfg.factorLegend * Math.sin(i * cfg.radians / total)) - 60 * Math.sin(i * cfg.radians / total); |
| }; |
| })(this)).attr("y", (function(_this) { |
| return function(d, i) { |
| return cfg.h / 2 * (1 - Math.cos(i * cfg.radians / total)) - 20 * Math.cos(i * cfg.radians / total); |
| }; |
| })(this)); |
| d.forEach(function(y, x) { |
| var dataValues; |
| dataValues = []; |
| g.selectAll(".nodes").data(y, function(j, i) { |
| return dataValues.push([cfg.w / 2 * (1 - (parseFloat(Math.max(j.value, 0)) / cfg.maxValue) * cfg.factor * Math.sin(i * cfg.radians / total)), cfg.h / 2 * (1 - (parseFloat(Math.max(j.value, 0)) / cfg.maxValue) * cfg.factor * Math.cos(i * cfg.radians / total))]); |
| }); |
| dataValues.push(dataValues[0]); |
| g.selectAll(".area").data([dataValues]).enter().append("polygon").attr("class", "radar-chart-serie" + series).style("stroke-width", "2px").style("stroke", cfg.color[series]).attr("points", function(d) { |
| var ac, len2, pt, str; |
| str = ""; |
| for (ac = 0, len2 = d.length; ac < len2; ac++) { |
| pt = d[ac]; |
| str = str + pt[0] + "," + pt[1] + " "; |
| } |
| return str; |
| }).style("fill", (function(_this) { |
| return function(j, i) { |
| return cfg.color[series]; |
| }; |
| })(this)).style("fill-opacity", cfg.opacityArea).on('mouseover', function(d) { |
| var z; |
| z = "polygon." + d3.select(this).attr("class"); |
| g.selectAll("polygon").transition(200).style("fill-opacity", 0.1); |
| return g.selectAll(z).transition(200).style("fill-opacity", .7); |
| }).on('mouseout', function() { |
| return g.selectAll("polygon").transition(200).style("fill-opacity", cfg.opacityArea); |
| }); |
| return series++; |
| }); |
| series = 0; |
| d.forEach(function(y, x) { |
| g.selectAll(".nodes").data(y).enter().append("svg:circle").attr("class", "radar-chart-serie" + series).attr('r', cfg.radius).attr("alt", (function(_this) { |
| return function(j) { |
| return Math.max(j.value, 0); |
| }; |
| })(this)).attr("cx", function(j, i) { |
| var dataValues; |
| dataValues = dataValues || []; |
| dataValues.push([cfg.w / 2 * (1 - (parseFloat(Math.max(j.value, 0)) / cfg.maxValue) * cfg.factor * Math.sin(i * cfg.radians / total)), cfg.h / 2 * (1 - (parseFloat(Math.max(j.value, 0)) / cfg.maxValue) * cfg.factor * Math.cos(i * cfg.radians / total))]); |
| return cfg.w / 2 * (1 - (Math.max(j.value, 0) / cfg.maxValue) * cfg.factor * Math.sin(i * cfg.radians / total)); |
| }).attr("cy", function(j, i) { |
| return cfg.h / 2 * (1 - (Math.max(j.value, 0) / cfg.maxValue) * cfg.factor * Math.cos(i * cfg.radians / total)); |
| }).attr("data-id", (function(_this) { |
| return function(j) { |
| return j.axis; |
| }; |
| })(this)).style("fill", cfg.color[series]).style("fill-opacity", .9).on('mouseover', function(d) { |
| var newX, newY, z; |
| newX = parseFloat(d3.select(this).attr('cx')) - 10; |
| newY = parseFloat(d3.select(this).attr('cy')) - 5; |
| tooltip.attr('x', newX).attr('y', newY).text(Format(d.value)).transition(200).style('opacity', 1); |
| z = "polygon." + d3.select(this).attr("class"); |
| g.selectAll("polygon").transition(200).style("fill-opacity", 0.1); |
| return g.selectAll(z).transition(200).style("fill-opacity", .7); |
| }).on('mouseout', function() { |
| tooltip.transition(200).style('opacity', 0); |
| return g.selectAll("polygon").transition(200).style("fill-opacity", cfg.opacityArea); |
| }).append("svg:title").text((function(_this) { |
| return function(j) { |
| return Math.max(j.value, 0); |
| }; |
| })(this)); |
| return series++; |
| }); |
| tooltip = g.append('text').style('opacity', 0).style('font-family', 'sans-serif').style('font-size', '13px'); |
| legend = g.append("g").attr("class", "legend").attr("height", 100).attr("width", 200).attr('transform', 'translate(90,20)'); |
| legend.selectAll('rect').data(LegendOptions).enter().append("rect").attr("x", cfg.w - 65).attr("y", (function(_this) { |
| return function(d, i) { |
| return i * 20; |
| }; |
| })(this)).attr("width", 10).attr("height", 10).style("fill", (function(_this) { |
| return function(d, i) { |
| return cfg.color[i]; |
| }; |
| })(this)); |
| legend.selectAll('text').data(LegendOptions).enter().append("text").attr("x", cfg.w - 52).attr("y", (function(_this) { |
| return function(d, i) { |
| return i * 20 + 9; |
| }; |
| })(this)).attr("font-size", "11px").attr("fill", "#737373").text((function(_this) { |
| return function(d) { |
| return d; |
| }; |
| })(this)); |
| g.resize = function() { |
| return true; |
| }; |
| return [g, {}]; |
| }; |
| |
| chartWrapperButtons = { |
| generic: [ |
| { |
| id: 'download', |
| icon: 'fa fa-download', |
| title: "Export Image", |
| onclick: function(o) { |
| return chartToSvg(o); |
| } |
| }, { |
| id: 'svg', |
| icon: 'fa fa-archive', |
| title: "Export as SVG", |
| onclick: function(o) { |
| return chartToSvg(o, true); |
| } |
| }, { |
| id: 'dataview', |
| icon: 'fa fa-book', |
| title: "Data View", |
| onclick: function(o) { |
| return dataTable(o); |
| } |
| }, { |
| id: 'fullscreen', |
| icon: 'fa fa-plus-square', |
| title: "Switch to fullscreen", |
| onclick: function(o) { |
| return fScreen(o); |
| } |
| } |
| ], |
| line: [ |
| { |
| icon: 'fa fa-bar-chart', |
| title: "Show as Bar Chart", |
| onclick: function(o) { |
| return switchChartType(o, o.config, 'bar'); |
| } |
| }, { |
| icon: 'fa fa-line-chart', |
| title: "Show as Line Chart", |
| onclick: function(o) { |
| return switchChartType(o, o.config, 'line'); |
| } |
| }, { |
| icon: 'fa fa-area-chart', |
| title: "Show as Area Chart", |
| onclick: function(o) { |
| return switchChartType(o, o.config, 'area-spline'); |
| } |
| }, { |
| icon: 'fa fa-bars', |
| title: "Stack values", |
| onclick: function(o) { |
| return stackChart(o, o.config, o.chartobj); |
| } |
| }, { |
| icon: 'fa fa-object-ungroup', |
| title: "Show sub-chart", |
| onclick: function(o) { |
| o.config.subchart = { |
| show: o.config.subchart && o.config.subchart.show ? false : true |
| }; |
| return o.chartobj = c3.generate(o.config); |
| } |
| } |
| ] |
| }; |
| |
| xxCharts = {}; |
| |
| fScreen = function(o) { |
| var bb, xclass; |
| xclass = o.main.getAttribute('class'); |
| if (!xclass.match('chartModal')) { |
| o.main.className = "chartModal chartWrapper"; |
| o.main.style.minHeight = "100% !important"; |
| o.buttons['fullscreen'].childNodes[0].className = 'fa fa-minus-square'; |
| o.buttons['fullscreen'].title = "Restore window"; |
| o.main.childNodes[2].style.minHeight = (window.innerHeight - 60) + "px"; |
| if (o.config.donut) { |
| o.config.donut.width = 120; |
| switchChartType(o, o.config, 'donut'); |
| } |
| if (o.config.linked) { |
| bb = o.main.childNodes[2].getBoundingClientRect(); |
| o.chartobj.resize({ |
| height: bb.height |
| }); |
| } else { |
| o.chartobj.resize({ |
| height: 720 |
| }); |
| } |
| } else { |
| o.main.className = "chartWrapper"; |
| o.main.childNodes[2].style.minHeight = ""; |
| o.buttons['fullscreen'].title = "Switch to fullscreen"; |
| o.buttons['fullscreen'].childNodes[0].className = 'fa fa-plus-square'; |
| if (o.config.donut) { |
| o.config.donut.width = 50; |
| switchChartType(o, o.config, 'donut'); |
| } |
| if (o.config.linked) { |
| bb = o.main.childNodes[2].getBoundingClientRect(); |
| o.chartobj.resize({ |
| height: bb.height |
| }); |
| } else { |
| o.chartobj.resize({ |
| height: 240 |
| }); |
| } |
| } |
| return true; |
| }; |
| |
| copyCSS = function(destination, source) { |
| var cd, child, containerElements, q, ref, ref1, results, st, style; |
| containerElements = ["svg", "g"]; |
| if (destination.childNodes.length > 0) { |
| results = []; |
| for (cd = q = 0, ref = destination.childNodes.length - 1; 0 <= ref ? q <= ref : q >= ref; cd = 0 <= ref ? ++q : --q) { |
| child = destination.childNodes[cd]; |
| if ((ref1 = child.tagName, indexOf.call(containerElements, ref1) >= 0)) { |
| copyCSS(child, source.childNodes[cd]); |
| continue; |
| } |
| style = source.childNodes[cd].currentStyle || window.getComputedStyle(source.childNodes[cd]); |
| if (style === "undefined" || style === null) { |
| continue; |
| } |
| results.push((function() { |
| var len, results1, u; |
| results1 = []; |
| for (u = 0, len = style.length; u < len; u++) { |
| st = style[u]; |
| results1.push(child.style.setProperty(st, style.getPropertyValue(st))); |
| } |
| return results1; |
| })()); |
| } |
| return results; |
| } |
| }; |
| |
| downloadBlob = function(name, uri) { |
| var blob, e, saveLink, url; |
| if (navigator.msSaveOrOpenBlob) { |
| return navigator.msSaveOrOpenBlob(uriToBlob(uri), name); |
| } else { |
| saveLink = document.createElement('a'); |
| saveLink.download = name; |
| saveLink.style.display = 'none'; |
| document.body.appendChild(saveLink); |
| try { |
| blob = uriToBlob(uri); |
| url = URL.createObjectURL(blob); |
| saveLink.href = url; |
| saveLink.onclick = function() { |
| return requestAnimationFrame(function() { |
| return URL.revokeObjectURL(url); |
| }); |
| }; |
| } catch (_error) { |
| e = _error; |
| console.warn('This browser does not support object URLs. Falling back to string URL.'); |
| saveLink.href = uri; |
| } |
| saveLink.click(); |
| return document.body.removeChild(saveLink); |
| } |
| }; |
| |
| chartToSvg = function(o, asSVG) { |
| var blob, doctype, img, rect, source, svgcopy, svgdiv, url; |
| doctype = '<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">'; |
| svgdiv = o.chartdiv.getElementsByTagName('svg')[0]; |
| svgcopy = svgdiv.cloneNode(true); |
| copyCSS(svgcopy, svgdiv); |
| rect = o.main.getBoundingClientRect(); |
| svgcopy.setAttribute('xlink', 'http://www.w3.org/1999/xlink'); |
| source = (new XMLSerializer()).serializeToString(svgcopy); |
| source = source.replace(/(\w+)?:?xlink=/g, 'xmlns:xlink='); |
| source = source.replace(/NS\d+:href/g, 'xlink:href'); |
| blob = new Blob([doctype + source], { |
| type: 'image/svg+xml;charset=utf-8' |
| }); |
| url = window.URL.createObjectURL(blob); |
| if (asSVG) { |
| return downloadBlob('chart.svg', url); |
| } else { |
| img = new HTML('img', { |
| width: rect.width, |
| height: rect.height, |
| src: url |
| }); |
| img.onload = function() { |
| var canvas, canvasUrl, ctx; |
| canvas = new HTML('canvas', { |
| width: rect.width, |
| height: rect.height |
| }); |
| document.getElementById('chartWrapperHiddenMaster').appendChild(canvas); |
| ctx = canvas.getContext('2d'); |
| ctx.drawImage(img, 0, 0); |
| canvasUrl = canvas.toDataURL("image/png"); |
| return downloadBlob('chart.png', canvasUrl); |
| }; |
| return document.getElementById('chartWrapperHiddenMaster').appendChild(img); |
| } |
| }; |
| |
| rotateTable = function(list) { |
| var arr, el, i, len, len1, newList, q, ref, u, x; |
| newList = []; |
| ref = list[0]; |
| for (i = q = 0, len = ref.length; q < len; i = ++q) { |
| x = ref[i]; |
| arr = []; |
| for (u = 0, len1 = list.length; u < len1; u++) { |
| el = list[u]; |
| arr.push(el[i]); |
| } |
| newList.push(arr); |
| } |
| return newList; |
| }; |
| |
| dataTable = function(o) { |
| var arr, close, el, len, len1, modal, modalInner, myList, q, tbl, td, tr, u; |
| modal = new HTML('div', { |
| "class": "chartModal" |
| }); |
| modalInner = new HTML('div', { |
| "class": "chartModalContent" |
| }); |
| close = new HTML('span', { |
| "class": "chartModelClose", |
| onclick: "this.parentNode.parentNode.parentNode.removeChild(this.parentNode.parentNode);" |
| }, "X"); |
| modalInner.inject(close); |
| modal.inject(modalInner); |
| tbl = new HTML('table', { |
| border: "1" |
| }); |
| myList = o.config.data.columns; |
| if (myList[0].length > myList.length) { |
| myList = rotateTable(myList); |
| } |
| for (q = 0, len = myList.length; q < len; q++) { |
| arr = myList[q]; |
| tr = new HTML('tr'); |
| for (u = 0, len1 = arr.length; u < len1; u++) { |
| el = arr[u]; |
| if (el instanceof Date) { |
| el = el.toISOString().slice(0, 10); |
| } |
| td = new HTML('td', {}, String(el)); |
| tr.inject(td); |
| } |
| tbl.inject(tr); |
| } |
| modalInner.inject(tbl); |
| return document.body.appendChild(modal); |
| }; |
| |
| chartOnclick = function(func, cid) { |
| var xchart; |
| xchart = xxCharts[cid]; |
| return func(xchart); |
| }; |
| |
| switchChartType = function(o, config, type) { |
| var k, m, ref, v, xtype; |
| ref = config.data.types; |
| for (k in ref) { |
| v = ref[k]; |
| xtype = type; |
| m = type.match(/^(.+)\*$/); |
| if (m) { |
| xtype = m[1] + v.split(/-/)[1] || v; |
| } |
| config.data.types[k] = xtype; |
| } |
| return o.chartobj = c3.generate(config); |
| }; |
| |
| stackChart = function(o, config, chart) { |
| var arr, k, ref, v; |
| arr = []; |
| ref = config.data.columns; |
| for (k in ref) { |
| v = ref[k]; |
| arr.push(v[0]); |
| } |
| if (config.data.groups[0].length > 0) { |
| config.data.groups = [[]]; |
| return chart.groups([[]]); |
| } else { |
| config.data.groups = [arr]; |
| return chart.groups([arr]); |
| } |
| }; |
| |
| Chart = (function() { |
| function Chart(parent, type, data, options) { |
| var btn, btnDiv, btns, chartWrapperColors, chk, cid, el, hObj, i, id, inner, label, len, len1, q, ref, ref1, ref2, ref3, ref4, ref5, u; |
| cid = parseInt(Math.random() * 1000000).toString(16); |
| this.cid = cid; |
| xxCharts[cid] = this; |
| this.main = new HTML('div', { |
| "class": "chartWrapper" |
| }); |
| this.main.xThis = this; |
| this.data = data; |
| this.toolbar = new HTML('div', { |
| "class": "chartToolbar" |
| }); |
| this.main.inject(this.toolbar); |
| this.titlebar = new HTML('div', { |
| "class": "chartTitle" |
| }, options && options.title ? options.title : ""); |
| this.main.inject(this.titlebar); |
| i = 0; |
| chartWrapperColors = genColors(16, 0.2, 0.75, true); |
| btns = chartWrapperButtons.generic.slice(0, 999); |
| if (type === 'line') { |
| ref = chartWrapperButtons.line; |
| for (q = 0, len = ref.length; q < len; q++) { |
| el = ref[q]; |
| btns.push(el); |
| } |
| } |
| this.buttons = {}; |
| for (u = 0, len1 = btns.length; u < len1; u++) { |
| btn = btns[u]; |
| btnDiv = new HTML('div', { |
| title: btn.title, |
| "class": "chartToolButton", |
| style: { |
| background: chartWrapperColors[i] |
| } |
| }); |
| inner = new HTML('i', { |
| "class": btn.icon |
| }); |
| if (btn.id) { |
| this.buttons[btn.id] = btnDiv; |
| } |
| btnDiv.inject(inner); |
| this.toolbar.inject(btnDiv); |
| if (btn.onclick) { |
| (function(btn, btnDiv) { |
| return btnDiv.addEventListener('click', function() { |
| return chartOnclick(btn.onclick, cid); |
| }); |
| })(btn, btnDiv); |
| } |
| i++; |
| } |
| this.chartdiv = new HTML('div', { |
| "class": "chartChart" |
| }); |
| this.main.inject(this.chartdiv); |
| if (parent) { |
| parent.appendChild(this.main); |
| } else { |
| hObj = document.getElementById('chartWrapperHiddenMaster'); |
| if (!hObj) { |
| hObj = new HTML('div', { |
| id: 'chartWrapperHiddenMaster', |
| style: { |
| visibility: "hidden" |
| } |
| }); |
| document.body.appendChild(hObj); |
| } |
| hObj.appendChild(this.main); |
| } |
| if (type === 'line') { |
| ref1 = charts_linechart(this.chartdiv, data, options), this.chartobj = ref1[0], this.config = ref1[1]; |
| } |
| if (type === 'donut') { |
| ref2 = charts_donutchart(this.chartdiv, data, 15), this.chartobj = ref2[0], this.config = ref2[1]; |
| } |
| if (type === 'gauge') { |
| ref3 = charts_gaugechart(this.chartdiv, data), this.chartobj = ref3[0], this.config = ref3[1]; |
| } |
| if (type === 'radar') { |
| ref4 = charts_radarchart(this.chartdiv, data), this.chartobj = ref4[0], this.config = ref4[1]; |
| } |
| if (type === 'relationship') { |
| ref5 = charts_linked(this.chartdiv, data.nodes, data.links, options), this.chartobj = ref5[0], this.config = ref5[1]; |
| } |
| if (data.distinguishable) { |
| id = Math.floor(Math.random() * 987654321).toString(16); |
| chk = document.createElement('input'); |
| chk.setAttribute("type", "checkbox"); |
| chk.setAttribute("id", id); |
| chk.style.marginLeft = '10px'; |
| if (globArgs.distinguish && globArgs.distinguish === 'true') { |
| chk.checked = true; |
| } |
| chk.addEventListener("change", function() { |
| var distinguish; |
| distinguish = null; |
| if (this.checked) { |
| distinguish = 'true'; |
| globArgs['distinguish'] = 'true'; |
| } |
| updateWidgets('line', null, { |
| distinguish: distinguish |
| }); |
| return updateWidgets('gauge', null, { |
| distinguish: distinguish |
| }); |
| }); |
| this.main.inject(mk('br')); |
| this.main.inject(chk); |
| label = document.createElement('label'); |
| label.setAttribute("for", id); |
| label.setAttribute("title", "Check this box to distinguish between sub-categories in this chart"); |
| chk.setAttribute("title", "Check this box to distinguish between sub-categories in this chart"); |
| label.style.paddingLeft = '5px'; |
| label.appendChild(document.createTextNode('Toggle category breakdown')); |
| this.main.inject(label); |
| } |
| if (data.relativeMode) { |
| id = Math.floor(Math.random() * 987654321).toString(16); |
| chk = document.createElement('input'); |
| chk.setAttribute("type", "checkbox"); |
| chk.setAttribute("id", id); |
| chk.style.marginLeft = '10px'; |
| if (globArgs.relative && globArgs.relative === 'true') { |
| chk.checked = true; |
| } |
| chk.addEventListener("change", function() { |
| var relative; |
| relative = null; |
| if (this.checked) { |
| relative = 'true'; |
| globArgs['relative'] = 'true'; |
| } |
| updateWidgets('line', null, { |
| relative: relative |
| }); |
| return updateWidgets('gauge', null, { |
| relative: relative |
| }); |
| }); |
| this.main.inject(mk('br')); |
| this.main.inject(chk); |
| label = document.createElement('label'); |
| label.setAttribute("for", id); |
| label.setAttribute("title", "Check this box to use relative weighting"); |
| chk.setAttribute("title", "Check this box to use relative weighting"); |
| label.style.paddingLeft = '5px'; |
| label.appendChild(document.createTextNode('Toggle relative/comparative mode')); |
| this.main.inject(label); |
| } |
| return this.main; |
| } |
| |
| return Chart; |
| |
| })(); |
| |
| hsl2rgb = function(h, s, l) { |
| var fract, min, sh, sv, switcher, v, vsf; |
| h = h % 1; |
| if (s > 1) { |
| s = 1; |
| } |
| if (l > 1) { |
| l = 1; |
| } |
| if (l <= 0.5) { |
| v = l * (1 + s); |
| } else { |
| v = l + s - l * s; |
| } |
| if (v === 0) { |
| return { |
| r: 0, |
| g: 0, |
| b: 0 |
| }; |
| } |
| min = 2 * l - v; |
| sv = (v - min) / v; |
| sh = (6 * h) % 6; |
| switcher = Math.floor(sh); |
| fract = sh - switcher; |
| vsf = v * sv * fract; |
| switch (switcher) { |
| case 0: |
| return { |
| r: v, |
| g: min + vsf, |
| b: min |
| }; |
| case 1: |
| return { |
| r: v - vsf, |
| g: v, |
| b: min |
| }; |
| case 2: |
| return { |
| r: min, |
| g: v, |
| b: min + vsf |
| }; |
| case 3: |
| return { |
| r: min, |
| g: v - vsf, |
| b: v |
| }; |
| case 4: |
| return { |
| r: min + vsf, |
| g: min, |
| b: v |
| }; |
| case 5: |
| return { |
| r: v, |
| g: min, |
| b: v - vsf |
| }; |
| } |
| return { |
| r: 0, |
| g: 0, |
| b: 0 |
| }; |
| }; |
| |
| genColors = function(numColors, saturation, lightness, hex) { |
| var baseHue, c, cls, h, i, q, ref; |
| cls = []; |
| baseHue = 1.02; |
| if (numColors <= 2) { |
| baseHue = 0.65; |
| } |
| for (i = q = 1, ref = numColors; 1 <= ref ? q <= ref : q >= ref; i = 1 <= ref ? ++q : --q) { |
| c = hsl2rgb(baseHue, saturation, lightness); |
| while (c.r > 0.8 && c.g > 0.8 && c.b > 0.8) { |
| baseHue -= 0.37; |
| if (baseHue < 0) { |
| baseHue += 1; |
| } |
| c = hsl2rgb(baseHue, saturation, lightness); |
| } |
| if (hex) { |
| h = "#" + ("00" + (~~(c.r * 255)).toString(16)).slice(-2) + ("00" + (~~(c.g * 255)).toString(16)).slice(-2) + ("00" + (~~(c.b * 255)).toString(16)).slice(-2); |
| cls.push(h); |
| } else { |
| cls.push({ |
| r: parseInt(c.r * 255), |
| g: parseInt(c.g * 255), |
| b: parseInt(c.b * 255) |
| }); |
| } |
| baseHue -= 0.37; |
| if (baseHue < 0) { |
| baseHue += 1; |
| } |
| } |
| return cls; |
| }; |
| |
| quickColors = function(num) { |
| var b, c, colors, g, pastel, ph, q, r, ref, x; |
| colors = []; |
| ph = 0; |
| for (x = q = 1, ref = num; 1 <= ref ? q <= ref : q >= ref; x = 1 <= ref ? ++q : --q) { |
| r = Math.random(); |
| g = Math.random(); |
| b = Math.random(); |
| pastel = 0.7; |
| r = (pastel + r) / 2; |
| g = (pastel + g) / 2; |
| b = (pastel + b) / 2; |
| c = "#" + ("00" + (~~(r * 205)).toString(16)).slice(-2) + ("00" + (~~(g * 205)).toString(16)).slice(-2) + ("00" + (~~(b * 205)).toString(16)).slice(-2); |
| colors.push(c); |
| } |
| return colors; |
| }; |
| |
| datepickers = {}; |
| |
| updateTimeseriesWidgets = function(range) { |
| var from, to; |
| if (range) { |
| from = range[0]; |
| to = range[1]; |
| globArgs.from = from; |
| globArgs.to = to; |
| updateWidgets('line', null, { |
| to: to, |
| from: from |
| }); |
| updateWidgets('top5', null, { |
| to: to, |
| from: from |
| }); |
| updateWidgets('factors', null, { |
| to: to, |
| from: from |
| }); |
| updateWidgets('trends', null, { |
| to: to, |
| from: from |
| }); |
| updateWidgets('donut', null, { |
| to: to, |
| from: from |
| }); |
| updateWidgets('gauge', null, { |
| to: to, |
| from: from |
| }); |
| updateWidgets('radar', null, { |
| to: to, |
| from: from |
| }); |
| updateWidgets('relationship', null, { |
| to: to, |
| from: from |
| }); |
| updateWidgets('treemap', null, { |
| to: to, |
| from: from |
| }); |
| updateWidgets('report', null, { |
| to: to, |
| from: from |
| }); |
| updateWidgets('mvp', null, { |
| to: to, |
| from: from |
| }); |
| updateWidgets('comstat', null, { |
| to: to, |
| from: from |
| }); |
| updateWidgets('worldmap', null, { |
| to: to, |
| from: from |
| }); |
| return updateWidgets('jsondump', null, { |
| to: to, |
| from: from |
| }); |
| } |
| }; |
| |
| datepicker = function(widget) { |
| var cgroup, controls, datePickerOptions, div, fieldset, form, group, i, id, input, now, span; |
| div = document.createElement('div'); |
| div.setAttribute("class", "well"); |
| form = document.createElement('form'); |
| div.appendChild(form); |
| fieldset = document.createElement('fieldset'); |
| form.appendChild(fieldset); |
| cgroup = document.createElement('div'); |
| cgroup.setAttribute("class", "control-group"); |
| fieldset.appendChild(cgroup); |
| controls = document.createElement('div'); |
| controls.setAttribute("class", "controls"); |
| cgroup.appendChild(controls); |
| group = document.createElement('div'); |
| group.setAttribute("class", "input-prepend input-group"); |
| controls.appendChild(group); |
| span = document.createElement('span'); |
| span.setAttribute("class", "add-on input-group-addon"); |
| group.appendChild(span); |
| i = document.createElement('i'); |
| i.setAttribute("class", "glyphicon glyphicon-calendar fa fa-calendar"); |
| span.appendChild(i); |
| input = document.createElement('input'); |
| input.setAttribute("type", "text"); |
| input.style.width = "240px"; |
| input.setAttribute("name", "date"); |
| input.setAttribute("class", "form-control"); |
| now = (globArgs.from ? moment(parseInt(globArgs.from) * 1000) : moment().subtract(6, 'months')).format('YYYY-MM-DD') + " to " + (globArgs.from ? moment(parseInt(globArgs.to) * 1000) : moment()).format('YYYY-MM-DD'); |
| input.setAttribute("value", now); |
| id = Math.floor(Math.random() * 987654321).toString(16); |
| input.setAttribute("id", id); |
| group.appendChild(input); |
| widget.inject(div); |
| datePickerOptions = { |
| startDate: globArgs.from ? moment(new Date(globArgs.from * 1000)) : moment().subtract(6, 'months'), |
| endDate: globArgs.to ? moment(new Date(globArgs.to * 1000)) : moment(), |
| minDate: '1970-01-01', |
| maxDate: '2020-01-01', |
| dateLimit: { |
| days: 365 |
| }, |
| showDropdowns: true, |
| showWeekNumbers: true, |
| timePicker: false, |
| timePickerIncrement: 1, |
| timePicker12Hour: true, |
| ranges: { |
| 'Today': [moment(), moment()], |
| 'Yesterday': [moment().subtract(1, 'days'), moment().subtract(1, 'days')], |
| 'Past Week': [moment().subtract(7, 'days'), moment().subtract(1, 'days')], |
| 'Past 30 Days': [moment().subtract(30, 'days'), moment().subtract(1, 'days')], |
| 'This Month': [moment().startOf('month'), moment().endOf('month')], |
| 'Last Month': [moment().subtract(1, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month')], |
| 'Last 3 Months': [moment().subtract(3, 'month'), moment()], |
| 'Last 6 Months': [moment().subtract(6, 'month'), moment()], |
| 'Last 12 Months': [moment().subtract(1, 'year'), moment()], |
| 'Last 2 Years': [moment().subtract(2, 'year'), moment()], |
| 'Last 5 Years': [moment().subtract(5, 'year'), moment()], |
| 'Last 10 Years': [moment().subtract(10, 'year'), moment()], |
| 'Last...Snoot Years': [moment(42300, 'X'), moment()] |
| }, |
| opens: 'left', |
| buttonClasses: ['btn btn-default'], |
| applyClass: 'btn-small btn-primary', |
| cancelClass: 'btn-small', |
| format: 'YYYY-MM-DD', |
| separator: ' to ', |
| locale: { |
| applyLabel: 'Submit', |
| cancelLabel: 'Clear', |
| fromLabel: 'From', |
| toLabel: 'To', |
| customRangeLabel: 'Custom', |
| daysOfWeek: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'], |
| monthNames: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], |
| firstDay: 1 |
| } |
| }; |
| return $('#' + id).daterangepicker(datePickerOptions, function(start, end, label) { |
| console.log(start._d.getTime() / 1000); |
| return updateTimeseriesWidgets([Math.floor(start._d.getTime() / 1000), Math.floor(end._d.getTime() / 1000)]); |
| }); |
| }; |
| |
| badModal = function(str) { |
| var btn, btndiv, modalBox, modalInner; |
| if (typeof str === 'object') { |
| str = str.message; |
| } |
| modalBox = new HTML('div', { |
| "class": "errorModal" |
| }); |
| document.body.appendChild(modalBox); |
| modalInner = new HTML('div', { |
| "class": "errorModalInner" |
| }, txt(str)); |
| modalBox.appendChild(modalInner); |
| btndiv = new HTML('div', { |
| style: { |
| textAlign: "center", |
| marginTop: "10px" |
| } |
| }, " "); |
| modalInner.inject(btndiv); |
| btn = new HTML('button', { |
| "class": "btn btn-lg btn-success", |
| onclick: "document.body.removeChild(this.parentNode.parentNode.parentNode);" |
| }, "Gotcha!"); |
| btndiv.inject(btn); |
| return window.setTimeout(function() { |
| modalInner.style.visibility = "visible"; |
| return modalInner.style.opacity = 1; |
| }, 10); |
| }; |
| |
| snap = badModal; |
| |
| explorer = function(json, state) { |
| var ID, chk, ezURL, h, id, item, label, len, len1, list, m, opt, org, q, ref, ref1, ref2, ref3, slen, u; |
| org = json.organisation; |
| h = document.createElement('h2'); |
| if (json.tag) { |
| org.name += " (Filter: " + json.tag + ")"; |
| } |
| h.appendChild(document.createTextNode("Exploring " + org.name + ":")); |
| state.widget.inject(h, true); |
| list = document.createElement('select'); |
| state.widget.inject(list); |
| opt = document.createElement('option'); |
| opt.value = ""; |
| slen = 0; |
| ref = json.sources; |
| for (q = 0, len = ref.length; q < len; q++) { |
| item = ref[q]; |
| if (((ref1 = item.type) === 'git' || ref1 === 'svn' || ref1 === 'gerrit' || ref1 === 'github') && item.noclone !== true) { |
| slen++; |
| } |
| } |
| opt.text = "All " + slen + " repositories"; |
| list.appendChild(opt); |
| json.sources.sort(function(a, b) { |
| if (a.sourceURL === b.sourceURL) { |
| return 0; |
| } else { |
| if (a.sourceURL > b.sourceURL) { |
| return 1; |
| } else { |
| return -1; |
| } |
| } |
| }); |
| ref2 = json.sources; |
| for (u = 0, len1 = ref2.length; u < len1; u++) { |
| item = ref2[u]; |
| if (((ref3 = item.type) === 'git' || ref3 === 'svn' || ref3 === 'gerrit' || ref3 === 'github') && item.noclone !== true) { |
| opt = document.createElement('option'); |
| opt.value = item.sourceID; |
| ezURL = null; |
| m = item.sourceURL.match(/^([a-z]+:\/\/.+?)[\/?]([^\/?]+)$/i); |
| if (m && m.length === 3) { |
| ezURL = m[2] + " - (" + m[1] + ")"; |
| } |
| opt.text = ezURL ? ezURL : item.sourceURL; |
| if (globArgs.source && globArgs.source === item.sourceID) { |
| opt.selected = 'selected'; |
| } |
| list.appendChild(opt); |
| } |
| } |
| ID = Math.floor(Math.random() * 987654321).toString(16); |
| list.setAttribute('id', ID); |
| $("#" + ID).chosen().change(function() { |
| var source; |
| source = this.value; |
| if (source === "") { |
| source = null; |
| } |
| globArgs.source = source; |
| updateWidgets('donut', null, { |
| source: source |
| }); |
| updateWidgets('gauge', null, { |
| source: source |
| }); |
| updateWidgets('line', null, { |
| source: source |
| }); |
| updateWidgets('contacts', null, { |
| source: source |
| }); |
| updateWidgets('top5', null, { |
| source: source |
| }); |
| updateWidgets('factors', null, { |
| source: source |
| }); |
| updateWidgets('trends', null, { |
| source: source |
| }); |
| updateWidgets('mvp', null, { |
| source: source |
| }); |
| updateWidgets('comstat', null, { |
| source: source |
| }); |
| return updateWidgets('jsondump', null, { |
| source: source |
| }); |
| }); |
| id = Math.floor(Math.random() * 987654321).toString(16); |
| chk = document.createElement('input'); |
| chk.setAttribute("type", "checkbox"); |
| chk.setAttribute("id", id); |
| chk.style.marginLeft = '10px'; |
| if (globArgs.author && globArgs.author === 'true') { |
| chk.checked = true; |
| } |
| chk.addEventListener("change", function() { |
| var author, unique; |
| unique = null; |
| if (this.checked) { |
| author = 'true'; |
| globArgs['author'] = 'true'; |
| } |
| updateWidgets('donut', null, { |
| author: author |
| }); |
| updateWidgets('gauge', null, { |
| author: author |
| }); |
| updateWidgets('line', null, { |
| author: author |
| }); |
| updateWidgets('contacts', null, { |
| author: author |
| }); |
| updateWidgets('top5', null, { |
| author: author |
| }); |
| updateWidgets('factors', null, { |
| author: author |
| }); |
| updateWidgets('trends', null, { |
| author: author |
| }); |
| updateWidgets('relationship', null, { |
| author: author |
| }); |
| updateWidgets('mvp', null, { |
| author: author |
| }); |
| updateWidgets('comstat', null, { |
| author: author |
| }); |
| return updateWidgets('jsondump', null, { |
| author: author |
| }); |
| }); |
| state.widget.inject(chk); |
| label = document.createElement('label'); |
| label.setAttribute("for", id); |
| label.setAttribute("title", "Check this box to authorships instead of committerships"); |
| chk.setAttribute("title", "Check this box to authorships instead of committerships"); |
| label.style.paddingLeft = '5px'; |
| label.appendChild(document.createTextNode('Show authors')); |
| return state.widget.inject(label); |
| }; |
| |
| sourceexplorer = function(json, state) { |
| var ID, div, ezURL, h, item, len, len1, list, m, opt, org, q, ref, ref1, slen, u; |
| org = json.organisation; |
| h = document.createElement('h4'); |
| if (json.tag) { |
| org.name += " (Filter: " + json.tag + ")"; |
| } |
| h.appendChild(document.createTextNode("Exploring " + org.name + ":")); |
| state.widget.inject(h, true); |
| div = new HTML('div', { |
| "class": "form-group" |
| }); |
| list = new HTML('select', { |
| "class": "form-control" |
| }); |
| div.inject(list); |
| state.widget.inject(div); |
| opt = document.createElement('option'); |
| opt.value = ""; |
| slen = 0; |
| ref = json.sources; |
| for (q = 0, len = ref.length; q < len; q++) { |
| item = ref[q]; |
| slen++; |
| } |
| opt.text = "All " + slen + " sources"; |
| list.appendChild(opt); |
| json.sources.sort(function(a, b) { |
| if (a.sourceURL === b.sourceURL) { |
| return 0; |
| } else { |
| if (a.sourceURL > b.sourceURL) { |
| return 1; |
| } else { |
| return -1; |
| } |
| } |
| }); |
| ref1 = json.sources; |
| for (u = 0, len1 = ref1.length; u < len1; u++) { |
| item = ref1[u]; |
| if (true) { |
| opt = document.createElement('option'); |
| opt.value = item.sourceID; |
| ezURL = null; |
| m = item.sourceURL.match(/^([a-z]+:\/\/.+?)[\/?]([^\/?]+)$/i); |
| if (m && m.length === 3) { |
| ezURL = m[2] + " - (" + m[1] + ")"; |
| } |
| opt.text = ezURL ? ezURL : item.sourceURL; |
| if (globArgs.source && globArgs.source === item.sourceID) { |
| opt.selected = 'selected'; |
| } |
| list.appendChild(opt); |
| } |
| } |
| ID = Math.floor(Math.random() * 987654321).toString(16); |
| list.setAttribute('id', ID); |
| return $("#" + ID).chosen().change(function() { |
| var source; |
| source = this.value; |
| if (source === "") { |
| source = null; |
| } |
| globArgs.source = source; |
| updateWidgets('donut', null, { |
| source: source |
| }); |
| updateWidgets('gauge', null, { |
| source: source |
| }); |
| updateWidgets('line', null, { |
| source: source |
| }); |
| updateWidgets('contacts', null, { |
| source: source |
| }); |
| updateWidgets('top5', null, { |
| source: source |
| }); |
| updateWidgets('factors', null, { |
| source: source |
| }); |
| updateWidgets('trends', null, { |
| source: source |
| }); |
| updateWidgets('mvp', null, { |
| source: source |
| }); |
| updateWidgets('comstat', null, { |
| source: source |
| }); |
| return updateWidgets('jsondump', null, { |
| author: author |
| }); |
| }); |
| }; |
| |
| mailexplorer = function(json, state) { |
| var ID, ezURL, h, item, len, len1, list, m, opt, org, q, ref, ref1, ref2, ref3, slen, u; |
| org = json.organisation; |
| h = document.createElement('h4'); |
| if (json.tag) { |
| org.name += " (Filter: " + json.tag + ")"; |
| } |
| h.appendChild(document.createTextNode("Exploring " + org.name + ":")); |
| state.widget.inject(h, true); |
| list = document.createElement('select'); |
| state.widget.inject(list); |
| opt = document.createElement('option'); |
| opt.value = ""; |
| slen = 0; |
| ref = json.sources; |
| for (q = 0, len = ref.length; q < len; q++) { |
| item = ref[q]; |
| if ((ref1 = item.type) === 'mail' || ref1 === 'ponymail' || ref1 === 'pipermail' || ref1 === 'hyperkitty') { |
| slen++; |
| } |
| } |
| opt.text = "All " + slen + " mailing lists"; |
| list.appendChild(opt); |
| json.sources.sort(function(a, b) { |
| if (a.sourceURL === b.sourceURL) { |
| return 0; |
| } else { |
| if (a.sourceURL > b.sourceURL) { |
| return 1; |
| } else { |
| return -1; |
| } |
| } |
| }); |
| ref2 = json.sources; |
| for (u = 0, len1 = ref2.length; u < len1; u++) { |
| item = ref2[u]; |
| if ((ref3 = item.type) === 'mail' || ref3 === 'ponymail' || ref3 === 'pipermail' || ref3 === 'hyperkitty') { |
| opt = document.createElement('option'); |
| opt.value = item.sourceID; |
| ezURL = null; |
| m = item.sourceURL.match(/^([a-z]+:\/\/.+?)[\/?]([^\/?]+)$/i); |
| if (m && m.length === 3) { |
| ezURL = m[2] + " - (" + m[1] + ")"; |
| } |
| opt.text = ezURL ? ezURL : item.sourceURL; |
| if (globArgs.source && globArgs.source === item.sourceID) { |
| opt.selected = 'selected'; |
| } |
| list.appendChild(opt); |
| } |
| } |
| ID = Math.floor(Math.random() * 987654321).toString(16); |
| list.setAttribute('id', ID); |
| return $("#" + ID).chosen().change(function() { |
| var source; |
| source = this.value; |
| if (source === "") { |
| source = null; |
| } |
| globArgs.source = source; |
| updateWidgets('donut', null, { |
| source: source |
| }); |
| updateWidgets('gauge', null, { |
| source: source |
| }); |
| updateWidgets('line', null, { |
| source: source |
| }); |
| updateWidgets('contacts', null, { |
| source: source |
| }); |
| updateWidgets('top5', null, { |
| source: source |
| }); |
| updateWidgets('factors', null, { |
| source: source |
| }); |
| updateWidgets('trends', null, { |
| source: source |
| }); |
| return updateWidgets('relationship', null, { |
| source: source |
| }); |
| }); |
| }; |
| |
| logexplorer = function(json, state) { |
| var ID, ezURL, h, item, len, len1, list, m, opt, org, q, ref, ref1, slen, u; |
| org = json.organisation; |
| h = document.createElement('h4'); |
| if (json.tag) { |
| org.name += " (Filter: " + json.tag + ")"; |
| } |
| h.appendChild(document.createTextNode("Exploring " + org.name + ":")); |
| state.widget.inject(h, true); |
| list = document.createElement('select'); |
| state.widget.inject(list); |
| opt = document.createElement('option'); |
| opt.value = ""; |
| slen = 0; |
| ref = json.sources; |
| for (q = 0, len = ref.length; q < len; q++) { |
| item = ref[q]; |
| if (item.type === 'stats') { |
| slen++; |
| } |
| } |
| opt.text = "All " + slen + " log files"; |
| list.appendChild(opt); |
| json.sources.sort(function(a, b) { |
| if (a.sourceURL === b.sourceURL) { |
| return 0; |
| } else { |
| if (a.sourceURL > b.sourceURL) { |
| return 1; |
| } else { |
| return -1; |
| } |
| } |
| }); |
| ref1 = json.sources; |
| for (u = 0, len1 = ref1.length; u < len1; u++) { |
| item = ref1[u]; |
| if (item.type === 'stats') { |
| opt = document.createElement('option'); |
| opt.value = item.sourceID; |
| ezURL = null; |
| m = item.sourceURL.match(/^([a-z]+:\/\/.+?)[\/?]([^\/?]+)$/i); |
| if (m && m.length === 3) { |
| ezURL = m[2] + " - (" + m[1] + ")"; |
| } |
| opt.text = ezURL ? ezURL : item.sourceURL; |
| if (globArgs.source && globArgs.source === item.sourceID) { |
| opt.selected = 'selected'; |
| } |
| list.appendChild(opt); |
| } |
| } |
| ID = Math.floor(Math.random() * 987654321).toString(16); |
| list.setAttribute('id', ID); |
| return $("#" + ID).chosen().change(function() { |
| var source; |
| source = this.value; |
| if (source === "") { |
| source = null; |
| } |
| globArgs.source = source; |
| updateWidgets('donut', null, { |
| source: source |
| }); |
| updateWidgets('gauge', null, { |
| source: source |
| }); |
| updateWidgets('line', null, { |
| source: source |
| }); |
| updateWidgets('worldmap', null, { |
| source: source |
| }); |
| updateWidgets('top5', null, { |
| source: source |
| }); |
| updateWidgets('factors', null, { |
| source: source |
| }); |
| return updateWidgets('trends', null, { |
| source: source |
| }); |
| }); |
| }; |
| |
| issueexplorer = function(json, state) { |
| var ID, ezURL, h, item, len, len1, list, m, n, opt, org, q, ref, ref1, ref2, ref3, slen, u; |
| org = json.organisation; |
| if (json.tag) { |
| org.name += " (Filter: " + json.tag + ")"; |
| } |
| h = document.createElement('h4'); |
| h.appendChild(document.createTextNode("Exploring " + org.name + ":")); |
| state.widget.inject(h, true); |
| list = document.createElement('select'); |
| state.widget.inject(list); |
| opt = document.createElement('option'); |
| opt.value = ""; |
| slen = 0; |
| ref = json.sources; |
| for (q = 0, len = ref.length; q < len; q++) { |
| item = ref[q]; |
| if ((ref1 = item.type) === 'jira' || ref1 === 'gerrit' || ref1 === 'github' || ref1 === 'bugzilla') { |
| slen++; |
| } |
| } |
| opt.text = "All " + slen + " issue tracker(s)"; |
| list.appendChild(opt); |
| json.sources.sort(function(a, b) { |
| if (a.sourceURL === b.sourceURL) { |
| return 0; |
| } else { |
| if (a.sourceURL > b.sourceURL) { |
| return 1; |
| } else { |
| return -1; |
| } |
| } |
| }); |
| ref2 = json.sources; |
| for (u = 0, len1 = ref2.length; u < len1; u++) { |
| item = ref2[u]; |
| if ((ref3 = item.type) === 'jira' || ref3 === 'gerrit' || ref3 === 'github' || ref3 === 'bugzilla') { |
| opt = document.createElement('option'); |
| opt.value = item.sourceID; |
| ezURL = null; |
| n = item.sourceURL.match(/^([a-z]+:\/\/.+?)\/([-.A-Z0-9]+)$/i); |
| m = item.sourceURL.match(/^([a-z]+:\/\/.+?)\s(.+)$/i); |
| if (n && n.length === 3) { |
| ezURL = n[2] + " - (" + n[1] + ")"; |
| } else if (m && m.length === 3) { |
| ezURL = m[2] + " - (" + m[1] + ")"; |
| } |
| opt.text = ezURL ? ezURL : item.sourceURL; |
| if (globArgs.source && globArgs.source === item.sourceID) { |
| opt.selected = 'selected'; |
| } |
| list.appendChild(opt); |
| } |
| } |
| ID = Math.floor(Math.random() * 987654321).toString(16); |
| list.setAttribute('id', ID); |
| return $("#" + ID).chosen().change(function() { |
| var source; |
| source = this.value; |
| if (source === "") { |
| source = null; |
| } |
| globArgs.source = source; |
| updateWidgets('donut', null, { |
| source: source |
| }); |
| updateWidgets('gauge', null, { |
| source: source |
| }); |
| updateWidgets('line', null, { |
| source: source |
| }); |
| updateWidgets('contacts', null, { |
| source: source |
| }); |
| updateWidgets('top5', null, { |
| source: source |
| }); |
| updateWidgets('factors', null, { |
| source: source |
| }); |
| return updateWidgets('trends', null, { |
| source: source |
| }); |
| }); |
| }; |
| |
| forumexplorer = function(json, state) { |
| var ID, ezURL, h, item, len, len1, list, m, n, opt, org, q, ref, ref1, ref2, ref3, slen, u; |
| org = json.organisation; |
| if (json.tag) { |
| org.name += " (Filter: " + json.tag + ")"; |
| } |
| h = document.createElement('h4'); |
| h.appendChild(document.createTextNode("Exploring " + org.name + ":")); |
| state.widget.inject(h, true); |
| list = document.createElement('select'); |
| state.widget.inject(list); |
| opt = document.createElement('option'); |
| opt.value = ""; |
| slen = 0; |
| ref = json.sources; |
| for (q = 0, len = ref.length; q < len; q++) { |
| item = ref[q]; |
| if ((ref1 = item.type) === 'forum' || ref1 === 'discourse' || ref1 === 'askbot') { |
| slen++; |
| } |
| } |
| opt.text = "All " + slen + " forum(s)"; |
| list.appendChild(opt); |
| json.sources.sort(function(a, b) { |
| if (a.sourceURL === b.sourceURL) { |
| return 0; |
| } else { |
| if (a.sourceURL > b.sourceURL) { |
| return 1; |
| } else { |
| return -1; |
| } |
| } |
| }); |
| ref2 = json.sources; |
| for (u = 0, len1 = ref2.length; u < len1; u++) { |
| item = ref2[u]; |
| if ((ref3 = item.type) === 'forum' || ref3 === 'discourse' || ref3 === 'askbot') { |
| opt = document.createElement('option'); |
| opt.value = item.sourceID; |
| ezURL = null; |
| n = item.sourceURL.match(/^([a-z]+:\/\/.+?)\/([-.A-Z0-9]+)$/i); |
| m = item.sourceURL.match(/^([a-z]+:\/\/.+?)\s(.+)$/i); |
| if (n && n.length === 3) { |
| ezURL = n[2] + " - (" + n[1] + ")"; |
| } else if (m && m.length === 3) { |
| ezURL = m[2] + " - (" + m[1] + ")"; |
| } |
| opt.text = ezURL ? ezURL : item.sourceURL; |
| if (globArgs.source && globArgs.source === item.sourceID) { |
| opt.selected = 'selected'; |
| } |
| list.appendChild(opt); |
| } |
| } |
| ID = Math.floor(Math.random() * 987654321).toString(16); |
| list.setAttribute('id', ID); |
| return $("#" + ID).chosen().change(function() { |
| var source; |
| source = this.value; |
| if (source === "") { |
| source = null; |
| } |
| globArgs.source = source; |
| updateWidgets('donut', null, { |
| source: source |
| }); |
| updateWidgets('gauge', null, { |
| source: source |
| }); |
| updateWidgets('line', null, { |
| source: source |
| }); |
| updateWidgets('contacts', null, { |
| source: source |
| }); |
| updateWidgets('top5', null, { |
| source: source |
| }); |
| updateWidgets('factors', null, { |
| source: source |
| }); |
| return updateWidgets('trends', null, { |
| source: source |
| }); |
| }); |
| }; |
| |
| imexplorer = function(json, state) { |
| var ID, ezURL, h, item, len, len1, list, m, n, opt, org, q, ref, ref1, ref2, ref3, slen, u; |
| org = json.organisation; |
| if (json.tag) { |
| org.name += " (Filter: " + json.tag + ")"; |
| } |
| h = document.createElement('h4'); |
| h.appendChild(document.createTextNode("Exploring " + org.name + ":")); |
| state.widget.inject(h, true); |
| list = document.createElement('select'); |
| state.widget.inject(list); |
| opt = document.createElement('option'); |
| opt.value = ""; |
| slen = 0; |
| ref = json.sources; |
| for (q = 0, len = ref.length; q < len; q++) { |
| item = ref[q]; |
| if ((ref1 = item.type) === 'irc' || ref1 === 'gitter') { |
| slen++; |
| } |
| } |
| opt.text = "All " + slen + " messaging sources"; |
| list.appendChild(opt); |
| json.sources.sort(function(a, b) { |
| if (a.sourceURL === b.sourceURL) { |
| return 0; |
| } else { |
| if (a.sourceURL > b.sourceURL) { |
| return 1; |
| } else { |
| return -1; |
| } |
| } |
| }); |
| ref2 = json.sources; |
| for (u = 0, len1 = ref2.length; u < len1; u++) { |
| item = ref2[u]; |
| if ((ref3 = item.type) === 'irc' || ref3 === 'gitter') { |
| opt = document.createElement('option'); |
| opt.value = item.sourceID; |
| ezURL = null; |
| n = item.sourceURL.match(/^([a-z]+:\/\/.+?)\/([#\S+]+)$/i); |
| m = item.sourceURL.match(/^([a-z]+:\/\/.+?)\s(.+)$/i); |
| if (n && n.length === 3) { |
| ezURL = n[2] + " - (" + n[1] + ")"; |
| } else if (m && m.length === 3) { |
| ezURL = m[2] + " - (" + m[1] + ")"; |
| } |
| opt.text = ezURL ? ezURL : item.sourceURL; |
| if (globArgs.source && globArgs.source === item.sourceID) { |
| opt.selected = 'selected'; |
| } |
| list.appendChild(opt); |
| } |
| } |
| ID = Math.floor(Math.random() * 987654321).toString(16); |
| list.setAttribute('id', ID); |
| $("#" + ID).chosen().change(function() { |
| var source; |
| source = this.value; |
| if (source === "") { |
| source = null; |
| } |
| globArgs.source = source; |
| updateWidgets('donut', null, { |
| source: source |
| }); |
| updateWidgets('gauge', null, { |
| source: source |
| }); |
| updateWidgets('line', null, { |
| source: source |
| }); |
| updateWidgets('contacts', null, { |
| source: source |
| }); |
| updateWidgets('top5', null, { |
| source: source |
| }); |
| updateWidgets('factors', null, { |
| source: source |
| }); |
| return updateWidgets('trends', null, { |
| source: source |
| }); |
| }, false); |
| return $('select').chosen(); |
| }; |
| |
| ciexplorer = function(json, state) { |
| var ID, ezURL, h, item, len, len1, list, m, n, opt, org, q, ref, ref1, ref2, ref3, slen, u; |
| org = json.organisation; |
| if (json.tag) { |
| org.name += " (Filter: " + json.tag + ")"; |
| } |
| h = document.createElement('h4'); |
| h.appendChild(document.createTextNode("Exploring " + org.name + ":")); |
| state.widget.inject(h, true); |
| list = document.createElement('select'); |
| state.widget.inject(list); |
| opt = document.createElement('option'); |
| opt.value = ""; |
| slen = 0; |
| ref = json.sources; |
| for (q = 0, len = ref.length; q < len; q++) { |
| item = ref[q]; |
| if ((ref1 = item.type) === 'jenkins' || ref1 === 'travis' || ref1 === 'buildbot') { |
| slen++; |
| } |
| } |
| opt.text = "All " + slen + " CI Services"; |
| list.appendChild(opt); |
| json.sources.sort(function(a, b) { |
| if (a.sourceURL === b.sourceURL) { |
| return 0; |
| } else { |
| if (a.sourceURL > b.sourceURL) { |
| return 1; |
| } else { |
| return -1; |
| } |
| } |
| }); |
| ref2 = json.sources; |
| for (u = 0, len1 = ref2.length; u < len1; u++) { |
| item = ref2[u]; |
| if ((ref3 = item.type) === 'jenkins' || ref3 === 'travis' || ref3 === 'buildbot') { |
| opt = document.createElement('option'); |
| opt.value = item.sourceID; |
| ezURL = null; |
| n = item.sourceURL.match(/^([a-z]+:\/\/.+?)\/([#\S+]+)$/i); |
| m = item.sourceURL.match(/^([a-z]+:\/\/.+?)\s(.+)$/i); |
| if (n && n.length === 3) { |
| ezURL = n[2] + " - (" + n[1] + ")"; |
| } else if (m && m.length === 3) { |
| ezURL = m[2] + " - (" + m[1] + ")"; |
| } |
| opt.text = ezURL ? ezURL : item.sourceURL; |
| if (globArgs.source && globArgs.source === item.sourceID) { |
| opt.selected = 'selected'; |
| } |
| list.appendChild(opt); |
| } |
| } |
| ID = Math.floor(Math.random() * 987654321).toString(16); |
| list.setAttribute('id', ID); |
| return $("#" + ID).chosen().change(function() { |
| var source; |
| source = this.value; |
| if (source === "") { |
| source = null; |
| } |
| globArgs.source = source; |
| updateWidgets('donut', null, { |
| source: source |
| }); |
| updateWidgets('gauge', null, { |
| source: source |
| }); |
| updateWidgets('line', null, { |
| source: source |
| }); |
| updateWidgets('contacts', null, { |
| source: source |
| }); |
| updateWidgets('top5', null, { |
| source: source |
| }); |
| updateWidgets('factors', null, { |
| source: source |
| }); |
| updateWidgets('trends', null, { |
| source: source |
| }); |
| return updateWidgets('relationship', null, { |
| source: source |
| }); |
| }); |
| }; |
| |
| multiviewexplorer = function(json, state) { |
| var ID, h, item, k, list, opt, org, q, results, tName; |
| org = json.organisation; |
| h = document.createElement('h4'); |
| h.appendChild(document.createTextNode("Select views to compare:")); |
| state.widget.inject(h, true); |
| results = []; |
| for (k = q = 1; q <= 3; k = ++q) { |
| tName = 'tag' + k; |
| list = document.createElement('select'); |
| list.setAttribute("data", tName); |
| state.widget.inject(list); |
| opt = document.createElement('option'); |
| opt.value = ""; |
| opt.text = "(None)"; |
| list.appendChild(opt); |
| opt = document.createElement('option'); |
| opt.value = "---"; |
| opt.text = "Entire organisation"; |
| if (globArgs[tName] && globArgs[tName] === '---') { |
| opt.selected = 'selected'; |
| } |
| list.appendChild(opt); |
| if (isArray(json.views)) { |
| json.views.sort(function(a, b) { |
| if (a.name === b.name) { |
| return 0; |
| } else { |
| if (a.name > b.name) { |
| return 1; |
| } else { |
| return -1; |
| } |
| } |
| }); |
| } |
| results.push((function() { |
| var len, ref, results1, u; |
| ref = json.views; |
| results1 = []; |
| for (u = 0, len = ref.length; u < len; u++) { |
| item = ref[u]; |
| opt = document.createElement('option'); |
| opt.value = item.id; |
| opt.text = item.name; |
| if (globArgs[tName] && globArgs[tName] === item.id) { |
| opt.selected = 'selected'; |
| } |
| list.appendChild(opt); |
| ID = Math.floor(Math.random() * 987654321).toString(16); |
| list.setAttribute('id', ID); |
| results1.push($("#" + ID).chosen().change(function() { |
| var source, x; |
| source = this.value; |
| if (source === "") { |
| source = null; |
| } |
| tName = this.getAttribute("data"); |
| globArgs[tName] = source; |
| x = {}; |
| x[tName] = source; |
| updateWidgets('donut', null, x); |
| updateWidgets('gauge', null, x); |
| updateWidgets('line', null, x); |
| updateWidgets('contacts', null, x); |
| updateWidgets('top5', null, x); |
| updateWidgets('factors', null, x); |
| updateWidgets('trends', null, x); |
| return updateWidgets('radar', null, x); |
| })); |
| } |
| return results1; |
| })()); |
| } |
| return results; |
| }; |
| |
| subFilterGlob = null; |
| |
| subFilter = function() { |
| var source, tName, x; |
| source = subFilterGlob; |
| if (source === "") { |
| source = null; |
| } |
| tName = 'subfilter'; |
| globArgs[tName] = source; |
| x = {}; |
| x[tName] = source; |
| updateWidgets('sourcepicker', null, x); |
| updateWidgets('repopicker', null, x); |
| updateWidgets('issuepicker', null, x); |
| updateWidgets('forumpicker', null, x); |
| updateWidgets('mailpicker', null, x); |
| updateWidgets('logpicker', null, x); |
| updateWidgets('donut', null, x); |
| updateWidgets('gauge', null, x); |
| updateWidgets('line', null, x); |
| updateWidgets('contacts', null, x); |
| updateWidgets('top5', null, x); |
| updateWidgets('factors', null, x); |
| updateWidgets('trends', null, x); |
| updateWidgets('radar', null, x); |
| updateWidgets('widget', null, x); |
| updateWidgets('relationship', null, x); |
| updateWidgets('treemap', null, x); |
| updateWidgets('report', null, x); |
| updateWidgets('mvp', null, x); |
| updateWidgets('comstat', null, x); |
| updateWidgets('worldmap', null, x); |
| updateWidgets('jsondump', null, x); |
| return $("a").each(function() { |
| var m, url; |
| url = $(this).attr('href'); |
| if (url) { |
| m = url.match(/^(.+\?page=[-a-z]+.*?)(?:&subfilter=[^&]+)?(.*)$/); |
| if (m) { |
| if (source) { |
| return $(this).attr('href', m[1] + "&subfilter=" + source + m[2]); |
| } else { |
| return $(this).attr('href', "" + m[1] + m[2]); |
| } |
| } |
| } |
| }); |
| }; |
| |
| viewexplorer = function(json, state) { |
| var ID, b, div, h, i, item, len, list, opt, org, q, rb, ref, source, tName; |
| org = json.organisation; |
| h = document.createElement('h4'); |
| h.appendChild(document.createTextNode("Select a view to use:")); |
| state.widget.inject(h, true); |
| tName = 'view'; |
| list = document.createElement('select'); |
| list.setAttribute("data", tName); |
| state.widget.inject(list); |
| opt = document.createElement('option'); |
| opt.value = ""; |
| opt.text = "(None)"; |
| list.appendChild(opt); |
| opt = document.createElement('option'); |
| opt.value = "---"; |
| opt.text = "Entire organisation"; |
| if (globArgs[tName] && globArgs[tName] === '---') { |
| opt.selected = 'selected'; |
| } |
| list.appendChild(opt); |
| if (isArray(json.views)) { |
| json.views.sort(function(a, b) { |
| if (a.name === b.name) { |
| return 0; |
| } else { |
| if (a.name > b.name) { |
| return 1; |
| } else { |
| return -1; |
| } |
| } |
| }); |
| } |
| ref = json.views; |
| for (q = 0, len = ref.length; q < len; q++) { |
| item = ref[q]; |
| opt = document.createElement('option'); |
| opt.value = item.id; |
| opt.text = item.name; |
| if (globArgs[tName] && globArgs[tName] === item.id) { |
| opt.selected = 'selected'; |
| } |
| list.appendChild(opt); |
| } |
| ID = Math.floor(Math.random() * 987654321).toString(16); |
| list.setAttribute('id', ID); |
| $("#" + ID).chosen().change(function() { |
| var source, x; |
| source = this.value; |
| if (source === "") { |
| source = null; |
| } |
| tName = this.getAttribute("data"); |
| globArgs[tName] = source; |
| x = {}; |
| x[tName] = source; |
| updateWidgets('sourcepicker', null, x); |
| updateWidgets('repopicker', null, x); |
| updateWidgets('issuepicker', null, x); |
| updateWidgets('mailpicker', null, x); |
| updateWidgets('logpicker', null, x); |
| updateWidgets('donut', null, x); |
| updateWidgets('gauge', null, x); |
| updateWidgets('line', null, x); |
| updateWidgets('contacts', null, x); |
| updateWidgets('top5', null, x); |
| updateWidgets('factors', null, x); |
| updateWidgets('trends', null, x); |
| updateWidgets('radar', null, x); |
| updateWidgets('widget', null, x); |
| updateWidgets('relationship', null, x); |
| updateWidgets('treemap', null, x); |
| updateWidgets('report', null, x); |
| updateWidgets('mvp', null, x); |
| updateWidgets('comstat', null, x); |
| updateWidgets('worldmap', null, x); |
| updateWidgets('jsondump', null, x); |
| return $("a").each(function() { |
| var m, url; |
| url = $(this).attr('href'); |
| if (url) { |
| m = url.match(/^(.+\?page=[-a-z]+)(?:&view=[a-f0-9]+)?(.*)$/); |
| if (m) { |
| if (source) { |
| return $(this).attr('href', m[1] + "&view=" + source + m[2]); |
| } else { |
| return $(this).attr('href', "" + m[1] + m[2]); |
| } |
| } |
| } |
| }); |
| }); |
| state.widget.inject(new HTML('br')); |
| i = new HTML('input', { |
| id: 'subfilter', |
| size: 16, |
| type: 'text', |
| value: globArgs.subfilter, |
| onChange: 'subFilterGlob = this.value;', |
| placeholder: 'sub-filter' |
| }); |
| b = new HTML('input', { |
| style: { |
| marginLeft: '10px' |
| }, |
| "class": 'btn btn-small btn-success', |
| type: 'button', |
| onClick: 'subFilter();', |
| value: "sub-filter" |
| }); |
| rb = new HTML('input', { |
| style: { |
| marginLeft: '10px' |
| }, |
| "class": 'btn btn-small btn-danger', |
| type: 'button', |
| onClick: 'get("subfilter").value=""; subFilterGlob=""; subFilter();', |
| value: "reset" |
| }); |
| state.widget.inject(i); |
| state.widget.inject(b); |
| state.widget.inject(rb); |
| if (globArgs.subfilter && globArgs.subfilter.length > 0) { |
| source = globArgs.subfilter; |
| $("a").each(function() { |
| var m, url; |
| url = $(this).attr('href'); |
| if (url) { |
| m = url.match(/^(.+\?page=[-a-z]+.*?)(?:&subfilter=[a-f0-9]+)?(.*)$/); |
| if (m) { |
| if (source) { |
| return $(this).attr('href', m[1] + "&subfilter=" + source + m[2]); |
| } else { |
| return $(this).attr('href', "" + m[1] + m[2]); |
| } |
| } |
| } |
| }); |
| } |
| if (globArgs.email) { |
| div = new HTML('div', {}, "Currently filtering results based on " + globArgs.email + ". - "); |
| div.inject(new HTML('a', { |
| href: 'javascript:void(filterPerson(null));' |
| }, "Reset filter")); |
| return state.widget.inject(div); |
| } |
| }; |
| |
| widgetexplorer = function(json, state) { |
| var h, key, list, opt, org, pwidgets, tName, value; |
| pwidgets = { |
| 'languages': 'Code: Language breakdown', |
| 'commit-history-year': "Code: Commit history (past year)", |
| 'commit-history-all': "Code: Commit history (all time)", |
| 'commit-top5-year': "Code: top 5 committers (past year)", |
| 'commit-top5-all': "Code: top 5 committers (all time)", |
| 'committer-count-year': "Code: Committers/Authors per month (past year)", |
| 'committer-count-all': "Code: Committers/Authors per month (all time)", |
| 'commit-lines-year': "Code: Lines changed (past year)", |
| 'commit-lines-all': "Code: Lines changed (all time)", |
| 'sloc-map': "Code: Language Treemap", |
| 'repo-size-year': "Repos: top 15 by lines of code", |
| 'repo-commits-year': "Repos: top 15 by number of commits (past year)", |
| 'repo-commits-all': "Repos: top 15 by number of commits (all time)", |
| 'evolution': "Code: Code evolution (all time)", |
| 'evolution-extended': "Code: Code evolution (individual languages, all time)", |
| 'issue-count-year': "Issues: Tickets opened/closed (past year)", |
| 'issue-count-all': "Issues: Tickets opened/closed (all time)", |
| 'issue-operators-year': "Issues: Ticket creators/closers (past year)", |
| 'issue-operators-all': "Issues: Ticket creators/closers (all time)", |
| 'issue-queue-all': "Issue queue size by ticket age", |
| 'email-count-year': "Mail: Emails/threads/authors (past year)", |
| 'email-count-all': "Mail: Emails/threads/authors (all time)", |
| 'im-stats-year': "Online messaging activity (past year)", |
| 'im-stats-all': "Online messaging activity (all time)", |
| 'compare-commits-year': "Commits by Affiliation (past year)", |
| 'compare-commits-all': "Commits by Affiliation (all time)", |
| 'repo-relationship-year': "Repository relationships (past year)", |
| 'repo-relationship-2year': "Repository relationships (past two years)", |
| 'issue-relationship-year': "Issue tracker relationships (past year)", |
| 'issue-relationship-2year': "Issue tracker relationships (past two years)", |
| 'log-stats-year': "Downloads/Visits (past year)", |
| 'log-stats-all': "Downloads/Visits (all time)", |
| 'log-map-month': "Downloads/Visits per country (past month)", |
| 'log-map-year': "Downloads/Visits per country (past year)", |
| 'log-map-all': "Downloads/Visits per country (all time)" |
| }; |
| org = json.organisation; |
| h = document.createElement('h4'); |
| h.appendChild(document.createTextNode("Select a widget to use:")); |
| state.widget.inject(h, true); |
| tName = 'widget'; |
| list = document.createElement('select'); |
| list.setAttribute("data", tName); |
| state.widget.inject(list); |
| opt = document.createElement('option'); |
| opt.value = ""; |
| opt.text = "Select a widget type:"; |
| list.appendChild(opt); |
| for (key in pwidgets) { |
| value = pwidgets[key]; |
| opt = document.createElement('option'); |
| opt.value = key; |
| opt.text = value; |
| if (globArgs[tName] && globArgs[tName] === key) { |
| opt.selected = 'selected'; |
| } |
| list.appendChild(opt); |
| } |
| return list.addEventListener("change", function() { |
| var source, x; |
| source = this.value; |
| if (source === "") { |
| source = null; |
| } |
| tName = this.getAttribute("data"); |
| globArgs[tName] = source; |
| x = {}; |
| x[tName] = source; |
| updateWidgets('widget', null, x); |
| updateWidgets('donut', null, x); |
| updateWidgets('gauge', null, x); |
| updateWidgets('line', null, x); |
| updateWidgets('contacts', null, x); |
| updateWidgets('top5', null, x); |
| updateWidgets('factors', null, x); |
| updateWidgets('trends', null, x); |
| return updateWidgets('radar', null, x); |
| }, false); |
| }; |
| |
| keyValueForm = function(type, key, caption, placeholder) { |
| var div, inp, left, right; |
| div = new HTML('div', { |
| style: { |
| width: "100%", |
| margin: "10px", |
| paddingBottom: "10px" |
| } |
| }); |
| left = new HTML('div', { |
| style: { |
| float: "left", |
| width: "300px", |
| fontWeight: "bold" |
| } |
| }, caption); |
| right = new HTML('div', { |
| style: { |
| float: "left", |
| width: "500px" |
| } |
| }); |
| if (type === 'text') { |
| inp = new HTML('input', { |
| name: key, |
| id: key, |
| style: { |
| marginBottom: "10px" |
| }, |
| "class": "form-control", |
| type: "text", |
| placeholder: placeholder |
| }); |
| right.inject(inp); |
| } |
| if (type === 'textarea') { |
| inp = new HTML('textarea', { |
| name: key, |
| id: key, |
| style: { |
| marginBottom: "10px" |
| }, |
| "class": "form-control", |
| placeholder: placeholder |
| }); |
| right.inject(inp); |
| } |
| div.inject([left, right]); |
| return div; |
| }; |
| |
| orgCreated = function(json, state) { |
| if (json.okay) { |
| return location.reload(); |
| } |
| }; |
| |
| setDefaultOrg = function(orgid) { |
| return patch('account', { |
| email: userAccount.email, |
| defaultOrganisation: orgid |
| }, {}, defaultOrgChanged); |
| }; |
| |
| defaultOrgChanged = function(json, state) { |
| return window.setTimeout(function() { |
| return location.reload(); |
| }, 1000); |
| }; |
| |
| makeOrg = function() { |
| var orgdesc, orgid, orgname; |
| orgname = get('orgname').value; |
| orgdesc = get('orgdesc').value; |
| orgid = get('orgid').value; |
| if (orgid.length === 0) { |
| orgid = parseInt(Math.random() * 987654321).toString(16); |
| } |
| if (orgname.length === 0) { |
| alert("Please enter a name for the organisation!"); |
| return; |
| } |
| if (orgdesc.length === 0) { |
| alert("Please enter a description of the organisation!"); |
| return; |
| } |
| return put('org/list', { |
| id: orgid, |
| name: orgname, |
| desc: orgdesc |
| }, {}, orgCreated); |
| }; |
| |
| orglist = function(json, state) { |
| var btn, dbtn, div, fieldset, isDefault, items, legend, len, obj, odiv, org, q, ref; |
| items = []; |
| if (json.organisations.length === 0) { |
| obj = new HTML('div'); |
| obj.inject(new HTML('h3', {}, "You don't seem to belong to any organisations just yet.")); |
| if (userAccount.userlevel === 'admin') { |
| obj.inject("...but you can make one!"); |
| } |
| state.widget.inject(obj, true); |
| } else { |
| odiv = new HTML('div'); |
| ref = json.organisations; |
| for (q = 0, len = ref.length; q < len; q++) { |
| org = ref[q]; |
| isDefault = org.id === userAccount.defaultOrganisation; |
| div = new HTML('div', { |
| "class": "orgItem " + (isDefault ? "orgSelected" : "") |
| }); |
| div.inject(new HTML('h1', {}, org.name + (isDefault ? " (Current)" : ""))); |
| div.inject(new HTML('p', {}, org.description || "")); |
| div.inject([new HTML('kbd', {}, "" + org.docCount.pretty()), " objects collected from ", new HTML('kbd', {}, "" + org.sourceCount.pretty()), " sources so far."]); |
| odiv.inject(div); |
| if (!isDefault) { |
| dbtn = new HTML('input', { |
| style: { |
| marginTop: "10px", |
| width: "120px" |
| }, |
| "class": "btn btn-primary btn-block", |
| type: "button", |
| onclick: "setDefaultOrg('" + org.id + "');", |
| value: "Set as current" |
| }); |
| div.inject(dbtn); |
| } |
| odiv.inject(new HTML('hr')); |
| } |
| state.widget.inject(odiv, true); |
| } |
| if (userAccount.userlevel === "admin") { |
| fieldset = new HTML('fieldset', { |
| style: { |
| float: "left", |
| margin: '30px' |
| } |
| }); |
| legend = new HTML('legend', {}, "Create a new orgsanisation:"); |
| fieldset.inject(legend); |
| fieldset.inject(keyValueForm('text', 'orgname', 'Name of the organisation:', 'Foo, inc.')); |
| fieldset.inject(keyValueForm('textarea', 'orgdesc', 'Description:', 'Foo, inc. is awesome and does stuff.')); |
| fieldset.inject(keyValueForm('text', 'orgid', 'Optional org ID:', 'demo, myorg etc')); |
| fieldset.inject(new HTML('p', {}, "You'll be able to add users and owners once the organisation has been created.")); |
| btn = new HTML('input', { |
| style: { |
| width: "200px" |
| }, |
| "class": "btn btn-primary btn-block", |
| type: "button", |
| onclick: "makeOrg();", |
| value: "Create organisation" |
| }); |
| fieldset.inject(btn); |
| return state.widget.inject(fieldset); |
| } |
| }; |
| |
| inviteMember = function(eml, admin) { |
| return put('org/members', { |
| email: eml, |
| admin: admin |
| }, null, memberInvited); |
| }; |
| |
| removeMember = function(eml, admin) { |
| return xdelete('org/members', { |
| email: eml, |
| admin: admin |
| }, null, memberInvited); |
| }; |
| |
| memberInvited = function(json, state) { |
| return window.setTimeout(function() { |
| return location.reload(); |
| }, 1000); |
| }; |
| |
| membershipList = function(json, state) { |
| var admin, admopt, alink, btn, delopt, dlink, eml, h, inp, isAdmin, len, list, member, q, ref, tr; |
| h = new HTML('h3', {}, "Invite a member to " + userAccount.defaultOrganisation); |
| state.widget.inject(h, true); |
| inp = new HTML('input', { |
| id: "email", |
| type: "text", |
| placeholder: "email@ddres" |
| }); |
| btn = new HTML('input', { |
| type: 'button', |
| "class": 'btn btn-success', |
| value: "Invite member", |
| onclick: 'inviteMember(get("email").value, false);' |
| }); |
| state.widget.inject(inp); |
| state.widget.inject(btn); |
| state.widget.inject(new HTML('hr')); |
| h = new HTML('h3', {}, "Current membership of " + userAccount.defaultOrganisation + ":"); |
| state.widget.inject(h); |
| list = new HTML('table', { |
| style: { |
| margin: "20px", |
| border: "1px solid #666" |
| } |
| }); |
| ref = json.members; |
| for (q = 0, len = ref.length; q < len; q++) { |
| member = ref[q]; |
| tr = new HTML('tr', { |
| style: { |
| borderBottom: "1px solid #666" |
| } |
| }); |
| eml = new HTML('td', { |
| style: { |
| padding: "5px" |
| } |
| }, member); |
| isAdmin = indexOf.call(json.admins, member) >= 0; |
| admin = new HTML('td', { |
| style: { |
| padding: "5px" |
| } |
| }, isAdmin ? "Admin" : "Member"); |
| alink = new HTML('a', { |
| href: "javascript:void(inviteMember('" + member + "', true));" |
| }, "Make admin"); |
| if (isAdmin) { |
| alink = new HTML('a', { |
| href: "javascript:void(inviteMember('" + member + "', false));" |
| }, "Remove as admin"); |
| } |
| admopt = new HTML('td', { |
| style: { |
| padding: "5px" |
| } |
| }, alink); |
| dlink = new HTML('a', { |
| href: "javascript:void(removeMember('" + member + "'));" |
| }, "Remove from organisation"); |
| delopt = new HTML('td', { |
| style: { |
| padding: "5px" |
| } |
| }, dlink); |
| tr.inject(eml); |
| tr.inject(admin); |
| tr.inject(admopt); |
| tr.inject(delopt); |
| list.inject(tr); |
| } |
| return state.widget.inject(list); |
| }; |
| |
| API = 2; |
| |
| Number.prototype.pad = function(n) { |
| var str; |
| str = String(this); |
| if (str.length < n) { |
| str = "0".repeat(n - str.length) + str; |
| } |
| return str; |
| }; |
| |
| Number.prototype.pretty = function(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 = function(url, xstate, callback, nocreds) { |
| var xmlHttp; |
| xmlHttp = null; |
| if (window.XMLHttpRequest) { |
| xmlHttp = new XMLHttpRequest(); |
| } else { |
| xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); |
| } |
| if (!nocreds) { |
| xmlHttp.withCredentials = true; |
| } |
| xmlHttp.open("GET", "api/" + url, true); |
| xmlHttp.send(null); |
| return xmlHttp.onreadystatechange = function(state) { |
| var e, js, mpart, response; |
| if (xmlHttp.readyState === 4 && xmlHttp.status === 500) { |
| if (snap) { |
| snap(xstate); |
| } |
| return; |
| } |
| if (xmlHttp.readyState === 4 && xmlHttp.status >= 400) { |
| js = JSON.parse(xmlHttp.responseText); |
| if (js.code === 403) { |
| mpart = location.href.match(/\/\/[^\/]+\/(.+)$/)[1]; |
| location.href = "login.html?redirect=" + mpart; |
| } |
| badModal(js.reason); |
| return; |
| } |
| if (xmlHttp.readyState === 4 && xmlHttp.status === 200) { |
| if (callback) { |
| try { |
| response = JSON.parse(xmlHttp.responseText); |
| return callback(response, xstate); |
| } catch (_error) { |
| e = _error; |
| return callback(JSON.parse(xmlHttp.responseText), xstate); |
| } |
| } |
| } |
| }; |
| }; |
| |
| put = function(url, json, xstate, callback, nocreds) { |
| var xmlHttp; |
| if (nocreds == null) { |
| nocreds = false; |
| } |
| xmlHttp = null; |
| if (window.XMLHttpRequest) { |
| xmlHttp = new XMLHttpRequest(); |
| } else { |
| xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); |
| } |
| if (!nocreds) { |
| xmlHttp.withCredentials = true; |
| } |
| xmlHttp.open("PUT", "api/" + url, true); |
| xmlHttp.send(JSON.stringify(json || {})); |
| return xmlHttp.onreadystatechange = function(state) { |
| var e, js, response; |
| if (xmlHttp.readyState === 4 && xmlHttp.status === 500) { |
| if (snap) { |
| snap(xstate); |
| } |
| return; |
| } |
| if (xmlHttp.readyState === 4 && xmlHttp.status >= 400) { |
| js = JSON.parse(xmlHttp.responseText); |
| badModal(js.reason); |
| return; |
| } |
| if (xmlHttp.readyState === 4 && xmlHttp.status === 200) { |
| if (callback) { |
| try { |
| response = JSON.parse(xmlHttp.responseText); |
| if (response && response.loginRequired) { |
| location.href = "/login.html"; |
| return; |
| } |
| return callback(response, xstate); |
| } catch (_error) { |
| e = _error; |
| return callback(JSON.parse(xmlHttp.responseText), xstate); |
| } |
| } |
| } |
| }; |
| }; |
| |
| patch = function(url, json, xstate, callback, nocreds) { |
| var xmlHttp; |
| if (nocreds == null) { |
| nocreds = false; |
| } |
| xmlHttp = null; |
| if (window.XMLHttpRequest) { |
| xmlHttp = new XMLHttpRequest(); |
| } else { |
| xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); |
| } |
| if (!nocreds) { |
| xmlHttp.withCredentials = true; |
| } |
| xmlHttp.open("PATCH", "api/" + url, true); |
| xmlHttp.send(JSON.stringify(json || {})); |
| return xmlHttp.onreadystatechange = function(state) { |
| var e, js, response; |
| if (xmlHttp.readyState === 4 && xmlHttp.status === 500) { |
| if (snap) { |
| snap(xstate); |
| } |
| return; |
| } |
| if (xmlHttp.readyState === 4 && xmlHttp.status >= 400) { |
| js = JSON.parse(xmlHttp.responseText); |
| badModal(js.reason); |
| return; |
| } |
| if (xmlHttp.readyState === 4 && xmlHttp.status === 200) { |
| if (callback) { |
| try { |
| response = JSON.parse(xmlHttp.responseText); |
| if (response && response.loginRequired) { |
| location.href = "/login.html"; |
| return; |
| } |
| return callback(response, xstate); |
| } catch (_error) { |
| e = _error; |
| return callback(JSON.parse(xmlHttp.responseText), xstate); |
| } |
| } |
| } |
| }; |
| }; |
| |
| xdelete = function(url, json, xstate, callback, nocreds) { |
| var xmlHttp; |
| if (nocreds == null) { |
| nocreds = false; |
| } |
| xmlHttp = null; |
| if (window.XMLHttpRequest) { |
| xmlHttp = new XMLHttpRequest(); |
| } else { |
| xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); |
| } |
| if (!nocreds) { |
| xmlHttp.withCredentials = true; |
| } |
| xmlHttp.open("DELETE", "api/" + url, true); |
| xmlHttp.send(JSON.stringify(json || {})); |
| return xmlHttp.onreadystatechange = function(state) { |
| var e, js, response; |
| if (xmlHttp.readyState === 4 && xmlHttp.status === 500) { |
| if (snap) { |
| snap(xstate); |
| } |
| return; |
| } |
| if (xmlHttp.readyState === 4 && xmlHttp.status >= 400) { |
| js = JSON.parse(xmlHttp.responseText); |
| badModal(js.reason); |
| return; |
| } |
| if (xmlHttp.readyState === 4 && xmlHttp.status === 200) { |
| if (callback) { |
| try { |
| response = JSON.parse(xmlHttp.responseText); |
| if (response && response.loginRequired) { |
| location.href = "/login.html"; |
| return; |
| } |
| return callback(response, xstate); |
| } catch (_error) { |
| e = _error; |
| return callback(JSON.parse(xmlHttp.responseText), xstate); |
| } |
| } |
| } |
| }; |
| }; |
| |
| post = function(url, json, xstate, callback, snap) { |
| var fdata, key, val, xmlHttp; |
| xmlHttp = null; |
| if (window.XMLHttpRequest) { |
| xmlHttp = new XMLHttpRequest(); |
| } else { |
| xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); |
| } |
| xmlHttp.withCredentials = true; |
| for (key in json) { |
| val = json[key]; |
| 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); |
| xmlHttp.open("POST", "api/" + url, true); |
| xmlHttp.setRequestHeader("Content-type", "application/json"); |
| xmlHttp.send(fdata); |
| return xmlHttp.onreadystatechange = function(state) { |
| var e, response; |
| if (xmlHttp.readyState === 4 && xmlHttp.status === 500) { |
| if (snap) { |
| snap(xstate); |
| } |
| } |
| if (xmlHttp.readyState === 4 && xmlHttp.status === 200) { |
| if (callback) { |
| try { |
| response = JSON.parse(xmlHttp.responseText); |
| if (xstate && xstate.widget) { |
| xstate.widget.json = response; |
| } |
| return callback(response, xstate); |
| } catch (_error) { |
| e = _error; |
| return callback(JSON.parse(xmlHttp.responseText), xstate); |
| } |
| } |
| } |
| }; |
| }; |
| |
| mk = function(t, s, tt) { |
| var k, len, q, r, v; |
| r = document.createElement(t); |
| if (s) { |
| for (k in s) { |
| v = s[k]; |
| if (v) { |
| r.setAttribute(k, v); |
| } |
| } |
| } |
| if (tt) { |
| if (typeof tt === "string") { |
| app(r, txt(tt)); |
| } else { |
| if (isArray(tt)) { |
| for (q = 0, len = tt.length; q < len; q++) { |
| k = tt[q]; |
| if (typeof k === "string") { |
| app(r, txt(k)); |
| } else { |
| app(r, k); |
| } |
| } |
| } else { |
| app(r, tt); |
| } |
| } |
| } |
| return r; |
| }; |
| |
| app = function(a, b) { |
| var item, len, q, results; |
| if (isArray(b)) { |
| results = []; |
| for (q = 0, len = b.length; q < len; q++) { |
| item = b[q]; |
| if (typeof item === "string") { |
| item = txt(item); |
| } |
| results.push(a.appendChild(item)); |
| } |
| return results; |
| } else { |
| return a.appendChild(b); |
| } |
| }; |
| |
| set = function(a, b, c) { |
| return a.setAttribute(b, c); |
| }; |
| |
| txt = function(a) { |
| return document.createTextNode(a); |
| }; |
| |
| get = function(a) { |
| return document.getElementById(a); |
| }; |
| |
| swi = function(obj) { |
| var switchery; |
| return switchery = new Switchery(obj, { |
| color: '#26B99A' |
| }); |
| }; |
| |
| cog = function(div, size) { |
| var i, idiv; |
| if (size == null) { |
| 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 = ""; |
| return 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 = function(value) { |
| return value && typeof value === 'object' && value instanceof Array && typeof value.length === 'number' && typeof value.splice === 'function' && !(value.propertyIsEnumerable('length')); |
| }; |
| |
| |
| /* isHash: function to detect if an object is a hash */ |
| |
| isHash = function(value) { |
| return value && typeof value === 'object' && !isArray(value); |
| }; |
| |
| HTML = (function() { |
| function HTML(type, params, children) { |
| |
| /* create the raw element, or clone if passed an existing element */ |
| var child, key, len, q, subkey, subval, val; |
| if (typeof type === 'object') { |
| this.element = type.cloneNode(); |
| } else { |
| this.element = document.createElement(type); |
| } |
| |
| /* If params have been passed, set them */ |
| if (isHash(params)) { |
| for (key in params) { |
| val = params[key]; |
| |
| /* Standard string value? */ |
| if (typeof val === "string" || typeof val === 'number') { |
| this.element.setAttribute(key, val); |
| } else if (isArray(val)) { |
| |
| /* Are we passing a list of data to set? concatenate then */ |
| this.element.setAttribute(key, val.join(" ")); |
| } else if (isHash(val)) { |
| |
| /* Are we trying to set multiple sub elements, like a style? */ |
| for (subkey in val) { |
| subval = val[subkey]; |
| if (!this.element[key]) { |
| throw "No such attribute, " + key + "!"; |
| } |
| this.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 === "string") { |
| this.element.inject(txt(children)); |
| } else { |
| |
| /* If children is an array of elems, iterate and add */ |
| if (isArray(children)) { |
| for (q = 0, len = children.length; q < len; q++) { |
| child = children[q]; |
| |
| /* String? Convert via txt() then */ |
| if (typeof child === "string") { |
| this.element.inject(txt(child)); |
| } else { |
| |
| /* Plain element, add normally */ |
| this.element.inject(child); |
| } |
| } |
| } else { |
| |
| /* Just a single element, add it */ |
| this.element.inject(children); |
| } |
| } |
| } |
| return this.element; |
| } |
| |
| return HTML; |
| |
| })(); |
| |
| |
| /** |
| * prototype injector for HTML elements: |
| * Example: mydiv.inject(otherdiv) |
| */ |
| |
| HTMLElement.prototype.inject = function(child) { |
| var item, len, q; |
| if (isArray(child)) { |
| for (q = 0, len = child.length; q < len; q++) { |
| item = child[q]; |
| if (typeof item === 'string') { |
| item = txt(item); |
| } |
| this.appendChild(item); |
| } |
| } else { |
| if (typeof child === 'string') { |
| child = txt(child); |
| } |
| this.appendChild(child); |
| } |
| return child; |
| }; |
| |
| Date.prototype.ISOBare = function() { |
| var M, d, h, m, y; |
| 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; |
| }; |
| |
| userAccount = { |
| foundation: "public" |
| }; |
| |
| pageID = 0; |
| |
| APIVERSION = 3; |
| |
| setupPage = function(json, state) { |
| var child, div, k, len, q, r, ref, results, row, v, widget; |
| $('#placeholder').remove(); |
| if (json.error) { |
| div = document.getElementById('innercontents'); |
| div.style.textAlign = 'center'; |
| div.innerHTML = "<a style='color: #D44; font-size: 100pt;'><i class='fa fa-warning'></i></a><br/><h3>An error occurred:</h3><p style='font-size: 12pt;'>" + json.error + "</p>"; |
| return; |
| } |
| document.title = json.title + " - Apache Warble"; |
| ref = json.rows; |
| results = []; |
| for (q = 0, len = ref.length; q < len; q++) { |
| r = ref[q]; |
| row = new Row(); |
| results.push((function() { |
| var len1, ref1, ref2, ref3, ref4, ref5, results1, u; |
| ref1 = r.children; |
| results1 = []; |
| for (u = 0, len1 = ref1.length; u < len1; u++) { |
| child = ref1[u]; |
| widget = new Widget(child.blocks || 3, child); |
| if (state.gargs) { |
| widget.args.eargs = widget.args.eargs || {}; |
| ref2 = state.gargs; |
| for (k in ref2) { |
| v = ref2[k]; |
| widget.args.eargs[k] = v; |
| } |
| } |
| widget.parent = row; |
| row.inject(widget); |
| if (child.eargs) { |
| ref3 = child.eargs; |
| for (k in ref3) { |
| v = ref3[k]; |
| widget.args.eargs[k] = v; |
| } |
| } |
| if (child.wargs) { |
| widget.wargs = {}; |
| ref4 = child.wargs; |
| for (k in ref4) { |
| v = ref4[k]; |
| widget.wargs[k] = v; |
| } |
| } |
| if ((ref5 = child.type) !== 'views' && ref5 !== 'sourcelist') { |
| widget.args.eargs.quick = 'true'; |
| } |
| switch (child.type) { |
| case 'datepicker': |
| results1.push(datepicker(widget)); |
| break; |
| case 'sourcepicker': |
| results1.push(widget.load(sourceexplorer)); |
| break; |
| case 'repopicker': |
| results1.push(widget.load(explorer)); |
| break; |
| case 'mailpicker': |
| results1.push(widget.load(mailexplorer)); |
| break; |
| case 'issuepicker': |
| results1.push(widget.load(issueexplorer)); |
| break; |
| case 'forumpicker': |
| results1.push(widget.load(forumexplorer)); |
| break; |
| case 'viewpicker': |
| results1.push(widget.load(viewexplorer)); |
| break; |
| case 'logpicker': |
| results1.push(widget.load(logexplorer)); |
| break; |
| case 'impicker': |
| results1.push(widget.load(imexplorer)); |
| break; |
| case 'logpicker': |
| results1.push(widget.load(logexplorer)); |
| break; |
| case 'cipicker': |
| results1.push(widget.load(ciexplorer)); |
| break; |
| case 'widgetpicker': |
| results1.push(widget.load(widgetexplorer)); |
| break; |
| case 'multiviewpicker': |
| results1.push(widget.load(multiviewexplorer)); |
| break; |
| case 'donut': |
| results1.push(widget.load(donut)); |
| break; |
| case 'gauge': |
| results1.push(widget.load(gauge)); |
| break; |
| case 'widget': |
| results1.push(widget.load(publisher)); |
| break; |
| case 'radar': |
| results1.push(widget.load(radar)); |
| break; |
| case 'top5': |
| results1.push(widget.load(top5)); |
| break; |
| case 'factors': |
| results1.push(widget.load(factors)); |
| break; |
| case 'trends': |
| results1.push(widget.load(trend)); |
| break; |
| case 'line': |
| results1.push(widget.load(linechart)); |
| break; |
| case 'bio': |
| results1.push(widget.load(bio)); |
| break; |
| case 'messages': |
| results1.push(widget.load(messages)); |
| break; |
| case 'sourcelist': |
| results1.push(widget.load(sourcelist)); |
| break; |
| case 'sourceadd': |
| results1.push(widget.load(sourceadd)); |
| break; |
| case 'contacts': |
| results1.push(setupPhonebook(widget, child)); |
| break; |
| case 'preferences': |
| results1.push(widget.load(preferences)); |
| break; |
| case 'orgadmin': |
| results1.push(widget.load(orgadmin)); |
| break; |
| case 'affiliations': |
| results1.push(widget.load(affiliation)); |
| break; |
| case 'views': |
| results1.push(widget.load(manageviews)); |
| break; |
| case 'paragraph': |
| results1.push(widget.load(paragraph)); |
| break; |
| case 'relationship': |
| results1.push(widget.load(relationship)); |
| break; |
| case 'treemap': |
| results1.push(widget.load(treemap)); |
| break; |
| case 'report': |
| results1.push(widget.load(report)); |
| break; |
| case 'mvp': |
| results1.push(widget.load(mvp)); |
| break; |
| case 'comstat': |
| results1.push(widget.load(comstat)); |
| break; |
| case 'worldmap': |
| results1.push(widget.load(worldmap)); |
| break; |
| case 'orglist': |
| results1.push(widget.load(orglist)); |
| break; |
| case 'membership': |
| results1.push(widget.load(membershipList)); |
| break; |
| case 'jsondump': |
| results1.push(widget.load(jsondump)); |
| break; |
| case 'clientlist': |
| results1.push(widget.load(clientlist)); |
| break; |
| default: |
| results1.push(void 0); |
| } |
| } |
| return results1; |
| })()); |
| } |
| return results; |
| }; |
| |
| loadPageWidgets = function(page, apiVersion) { |
| var col, i, idiv, m, ph; |
| if (!page) { |
| page = window.location.search.substr(1); |
| } |
| if (apiVersion) { |
| APIVERSION = apiVersion; |
| } |
| ph = document.createElement('div'); |
| ph.setAttribute("class", "row"); |
| ph.setAttribute("id", "placeholder"); |
| col = document.createElement('div'); |
| col.setAttribute("class", "col-md-12"); |
| ph.appendChild(col); |
| 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: 240pt !important; color: #AAB;"); |
| idiv.appendChild(i); |
| idiv.appendChild(document.createElement('br')); |
| idiv.appendChild(document.createTextNode('Loading, hang on tight..!')); |
| col.appendChild(idiv); |
| ph.appendChild(col); |
| document.getElementById('innercontents').innerHTML = ""; |
| document.getElementById('innercontents').appendChild(ph); |
| while (page.match(/([^=]+)=([^=&]+)&?/)) { |
| m = page.match(/([^=]+)=([^&=]+)&?/); |
| if (m) { |
| console.log(m[1] + "=" + m[2]); |
| globArgs[m[1]] = unescape(m[2]); |
| page = page.replace(m[0], ''); |
| } |
| } |
| if (globArgs.page) { |
| pageID = globArgs.page; |
| } |
| if (globArgs.view) { |
| $("a").each(function() { |
| var url; |
| url = $(this).attr('href'); |
| m = url.match(/^(.+\?page=[-a-z]+)(?:&view=[a-f0-9]+)?(.*)$/); |
| if (m) { |
| if (globArgs.view) { |
| return $(this).attr('href', m[1] + "&view=" + globArgs.view + m[2]); |
| } |
| } |
| }); |
| } |
| return fetch('session', null, renderAccountInfo); |
| }; |
| |
| renderAccountInfo = function(json, state) { |
| var div; |
| if (json.error) { |
| div = document.getElementById('innercontents'); |
| div.style.textAlign = 'center'; |
| div.innerHTML = "<a style='color: #D44; font-size: 100pt;'><i class='fa fa-warning'></i></a><br/><h3>An error occurred:</h3><p style='font-size: 12pt;'>" + json.error + "</p>"; |
| if (json.loginRequired) { |
| return location.href = "/login.html"; |
| } |
| } else { |
| userAccount = json; |
| return fetch('widgets/' + pageID, { |
| gargs: globArgs |
| }, setupPage); |
| } |
| }; |
| |
| phonebook_cached = {}; |
| |
| fetchPhonebook = function(args) { |
| var url, wargs; |
| if (args) { |
| wargs = JSON.stringify(args); |
| if (phonebook_cached[wargs]) { |
| renderPhonebook(phonebook_cached[wargs], args); |
| return; |
| } |
| } |
| args.widget.cog(); |
| url = "people/"; |
| return postJSON(url, args, args, renderPhonebook); |
| }; |
| |
| setupPhonebook = function(widget, w) { |
| return fetchPhonebook({ |
| widget: widget, |
| w: w, |
| letter: 'a', |
| project: w.target || "" |
| }); |
| }; |
| |
| renderPhonebook = function(json, state) { |
| var a, imgsrc, len, len1, letter, letters, li, people, person, q, rdiv, ref, row, tbl, u, ul, wargs; |
| wargs = JSON.stringify(state); |
| phonebook_cached[wargs] = json; |
| letters = "abcdefghijklmnopqrstuvwxyz".split(""); |
| row = document.createElement('div'); |
| row.setAttribute("class", "row"); |
| rdiv = document.createElement('div'); |
| rdiv.setAttribute("class", "col-md-12 col-sm-12 col-xs-12 text-center"); |
| ul = document.createElement('ul'); |
| ul.setAttribute("class", "pagination pagination-split"); |
| for (q = 0, len = letters.length; q < len; q++) { |
| letter = letters[q]; |
| li = document.createElement('li'); |
| a = document.createElement('a'); |
| a.setAttribute("href", "#"); |
| a.addEventListener("click", function() { |
| state.letter = this.childNodes[0].data.toLowerCase(); |
| return fetchPhonebook(state); |
| }, false); |
| a.appendChild(document.createTextNode(letter.toUpperCase())); |
| if (state.letter && letter === state.letter) { |
| li.setAttribute("class", "active"); |
| } |
| li.appendChild(a); |
| ul.appendChild(li); |
| } |
| rdiv.appendChild(ul); |
| row.appendChild(rdiv); |
| state.widget.inject(row, true); |
| row = mk('table', { |
| "class": "display" |
| }, mk('thead', {}, mk('tr', {}, [mk('th', {}, 'Avatar'), mk('th', {}, 'Name'), mk('th', {}, 'Email')]))); |
| people = []; |
| json.people.sort((function(_this) { |
| return function(a, b) { |
| if (a.name === b.name) { |
| return 0; |
| } else { |
| if (a.name > b.name) { |
| return 1; |
| } else { |
| return -1; |
| } |
| } |
| }; |
| })(this)); |
| a = 0; |
| ref = json.people; |
| for (u = 0, len1 = ref.length; u < len1; u++) { |
| person = ref[u]; |
| a++; |
| imgsrc = document.createElement('img'); |
| imgsrc.setAttribute("class", "img-circle img-responsive"); |
| imgsrc.setAttribute("onshow", "this.src = 'https://secure.gravatar.com/avatar/" + person.md5 + ".png?d=identicon'"); |
| people.push(["https://secure.gravatar.com/avatar/" + person.md5 + ".png?d=identicon", person.name, person.email]); |
| } |
| state.widget.inject(row); |
| return tbl = $(row).DataTable({ |
| serverSide: true, |
| searching: false, |
| lengthMenu: [[25, 50, 100], [25, 50, 100]], |
| columnDefs: [ |
| { |
| targets: 0, |
| data: "avatar", |
| render: function(data, type, full, meta) { |
| return '<img class="img-circle img-responsive" style="width: 24px; height: 24px;" src="' + full[0] + '"/>'; |
| } |
| }, { |
| targets: 1, |
| data: "email", |
| render: function(data, type, full, meta) { |
| return '<a href="?page=people&email=' + full[2] + '">' + full[1] + "</a>"; |
| } |
| } |
| ], |
| ajax: function(data, callback, settings) { |
| var aa, i, out, ref1, ref2; |
| out = []; |
| for (i = aa = ref1 = data.start, ref2 = data.start + data.length; ref1 <= ref2 ? aa < ref2 : aa > ref2; i = ref1 <= ref2 ? ++aa : --aa) { |
| out.push(people[i]); |
| } |
| return setTimeout(function() { |
| return callback({ |
| draw: data.draw, |
| data: out, |
| recordsTotal: people.length, |
| recordsFiltered: people.length |
| }); |
| }, 50); |
| } |
| }, { |
| scrollY: 200, |
| scroller: { |
| loadingIndicator: true |
| } |
| }); |
| |
| /* |
| card = document.createElement('div') |
| card.setAttribute("class", "col-md-3 col-sm-4 col-xs-12 profile_details") |
| well = document.createElement('div') |
| well.setAttribute("class", "well profile_view") |
| well.style.width = "100%" |
| card.appendChild(well) |
| |
| namecard = document.createElement('div') |
| namecard.setAttribute("class", "left col-xs-7") |
| img = document.createElement('div') |
| img.setAttribute("class", "right col-xs-5 text-center") |
| imgsrc = document.createElement('img') |
| imgsrc.setAttribute("class", "img-circle img-responsive") |
| imgsrc.setAttribute("src", "https://secure.gravatar.com/avatar/" + person.md5 + ".png?d=identicon") |
| img.appendChild(imgsrc) |
| well.appendChild(namecard) |
| well.appendChild(img) |
| a = document.createElement('a') |
| a.setAttribute('href', '?page=people&email=' + person.email) |
| name = document.createElement('h2') |
| name.appendChild(document.createTextNode(person.name)) |
| a.appendChild(name) |
| namecard.appendChild(a) |
| namecard.appendChild(document.createTextNode(person.email)) |
| groups = [] |
| if person.tags |
| for tag in person.tags |
| if tag != '_untagged' |
| groups.push(tag) |
| if groups.length > 0 |
| namecard.appendChild(mk('br')) |
| namecard.appendChild(txt("Part of: " + groups.join(", "))) |
| |
| row.appendChild(card) |
| */ |
| }; |
| |
| addsources = function(form) { |
| var creds, json, len, line, lines, noclone, q, rv; |
| rv = get('retval'); |
| cog(rv); |
| json = { |
| action: 'add', |
| sources: [] |
| }; |
| lines = form.sources.value.split(/\r?\n/g); |
| creds = null; |
| noclone = false; |
| if (form.noclone.checked) { |
| noclone = true; |
| } |
| if (form.auth.checked) { |
| creds = { |
| type: form.atype.value, |
| username: form.auser.value, |
| password: form.apass.value, |
| cookie: form.acookie.value |
| }; |
| } |
| for (q = 0, len = lines.length; q < len; q++) { |
| line = lines[q]; |
| if (line.length > 5) { |
| json.sources.push({ |
| organisation: userAccount.organisation, |
| sourceURL: line, |
| type: form.stype.value, |
| creds: creds, |
| noclone: noclone |
| }); |
| } |
| } |
| put('sources', json, null, sourceret); |
| return false; |
| }; |
| |
| redirs = function() { |
| return location.href = '?page=sources'; |
| }; |
| |
| sourceret = function(json, state) { |
| var rv; |
| rv = get('retval'); |
| if (json.completed) { |
| rv.style.fontSize = "20pt"; |
| rv.style.color = "#383"; |
| json.added = json.added || 0; |
| rv.innerHTML = json.added + " sources added"; |
| if (json.updated && json.updated > 0) { |
| rv.innerHTML += ", " + json.updated + " updated."; |
| } |
| if (json.unknowns && json.unknowns > 0) { |
| rv.innerHTML += ", " + json.unknowns + " sources could not be added (unknown source type?)"; |
| } |
| return window.setTimeout(redirs, 2000); |
| } else { |
| rv.style.fontSize = "20pt"; |
| rv.style.color = "#843"; |
| return rv.innerHTML = "<h2>Error: </h2>" + json.error; |
| } |
| }; |
| |
| deletesource = function(hash) { |
| var tr; |
| if (window.confirm("Are you sure you wish to delete this resource?\nNOTE: Not everything about this can be deleted. Due to the nature of especially git, the unique commit stats will NOT change when you delete a git resource until you force a complete reindex of everything.")) { |
| tr = get(hash); |
| tr.parentNode.removeChild(tr); |
| return xdelete('sources', { |
| id: hash |
| }, null, null); |
| } |
| }; |
| |
| sourceTypes = {}; |
| |
| getSourceType = function(main, t) { |
| var el, len, obj, q, ref, tbl, tbody, td, thead, tr; |
| if (!sourceTypes[t]) { |
| obj = new HTML('div', { |
| id: "source_" + t, |
| style: { |
| display: "none" |
| } |
| }); |
| tbl = mk('table'); |
| set(tbl, 'class', 'table table-striped'); |
| thead = mk('thead'); |
| tr = mk('tr'); |
| ref = ['Source', 'Progress', 'Last Update', 'Status', 'Actions']; |
| for (q = 0, len = ref.length; q < len; q++) { |
| el = ref[q]; |
| td = mk('th'); |
| if (el.match(/Last/)) { |
| td.style.width = "200px"; |
| td.style.textAlign = 'right'; |
| } |
| if (el.match(/Status/)) { |
| td.style.width = "600px"; |
| } |
| app(td, txt(el)); |
| app(tr, td); |
| } |
| app(thead, tr); |
| app(tbl, thead); |
| tbody = new HTML('tbody'); |
| app(tbl, tbody); |
| obj.inject(tbl); |
| main.inject(obj); |
| sourceTypes[t] = { |
| main: obj, |
| div: tbody, |
| count: 0 |
| }; |
| } |
| return sourceTypes[t]; |
| }; |
| |
| sourcelist = function(json, state) { |
| var aa, ab, act, borked, cl, color, d, dbtn, desc, div, el, firstRun, h, ic, icons, img, item, lastException, lastFailure, lastUpdate, len, len1, len2, len3, lu, m, q, ref, ref1, ref2, ref3, ref4, ref5, retval, running, slist, source, sources, st, status, steps, t, tbody, u, vlist; |
| slist = mk('div'); |
| vlist = new HTML('div'); |
| if (json.sources) { |
| sources = json.sources; |
| for (q = 0, len = sources.length; q < len; q++) { |
| source = sources[q]; |
| source.good = true; |
| source.running = false; |
| steps = ['sync', 'census', 'count', 'evolution']; |
| if (source.type === 'mail') { |
| steps = ['mail']; |
| } |
| if ((ref = source.type) === 'jira' || ref === 'bugzilla') { |
| steps = ['issues']; |
| } |
| if ((ref1 = source.type) === 'irc') { |
| steps = ['census']; |
| } |
| if (source.type === 'gerrit' || source.type === 'github') { |
| steps = ['issues', 'sync', 'census', 'count', 'evolution']; |
| } |
| for (u = 0, len1 = steps.length; u < len1; u++) { |
| item = steps[u]; |
| if (source.steps) { |
| if (source.steps[item] && source.steps[item].good === false) { |
| source.good = false; |
| } |
| if (source.steps[item] && source.steps[item].running) { |
| source.running = true; |
| } |
| } |
| } |
| } |
| sources = sources.sort ? sources : []; |
| sources.sort(function(a, b) { |
| return (a.running === b.running ? (a.good === b.good ? (a.sourceURL > b.sourceURL ? 1 : -1) : (b.good === true ? -1 : 1)) : (b.running === true ? 1 : -1)); |
| }); |
| for (aa = 0, len2 = sources.length; aa < len2; aa++) { |
| source = sources[aa]; |
| st = getSourceType(vlist, source.type); |
| tbody = st.div; |
| st.count++; |
| d = mk('tr'); |
| set(d, 'id', source.sourceID); |
| set(d, 'scope', 'row'); |
| t = mk('td'); |
| t.style.color = "#369"; |
| app(t, txt(source.sourceURL)); |
| app(d, t); |
| lastUpdate = 0; |
| lastFailure = null; |
| lastException = null; |
| running = null; |
| firstRun = 0; |
| icons = { |
| sync: 'fa fa-download', |
| census: 'fa fa-users', |
| count: 'fa fa-sitemap', |
| evolution: 'fa fa-signal', |
| mail: 'fa fa-envelope', |
| issues: 'fa fa-feed' |
| }; |
| t = new HTML('td', { |
| style: { |
| minWidth: "260px !important" |
| } |
| }); |
| borked = false; |
| steps = ['sync', 'census', 'count', 'evolution']; |
| if ((ref2 = source.type) === 'mail' || ref2 === 'ponymail' || ref2 === 'pipermail' || ref2 === 'hyperkitty') { |
| steps = ['mail']; |
| } |
| if ((ref3 = source.type) === 'jira' || ref3 === 'bugzilla') { |
| steps = ['issues']; |
| } |
| if ((ref4 = source.type) === 'gerrit' || ref4 === 'gitlab' || ref4 === 'github') { |
| steps = ['sync', 'census', 'count', 'evolution', 'issues']; |
| } |
| if ((ref5 = source.type) === 'irc' || ref5 === 'stats') { |
| steps = ['census']; |
| } |
| for (ab = 0, len3 = steps.length; ab < len3; ab++) { |
| item = steps[ab]; |
| color = "#394"; |
| cl = icons[item]; |
| if (!source.steps || !source.steps[item] || borked) { |
| color = "#777"; |
| desc = item + ": This step hasn't completed yet"; |
| } else { |
| if (source.steps[item].time > lastUpdate) { |
| lastUpdate = source.steps[item].time; |
| } |
| desc = source.steps[item].status; |
| if (source.steps[item].good === false) { |
| borked = true; |
| color = "#952"; |
| lastFailure = source.steps[item].status; |
| lastException = source.steps[item].exception; |
| } |
| if (source.steps[item].running) { |
| cl += " fa-bubble"; |
| running = source.steps[item].status; |
| color = "#359"; |
| } |
| } |
| ic = mk('i'); |
| ic.style.padding = "10px"; |
| ic.style.fontSize = "20pt"; |
| set(ic, 'class', cl); |
| set(ic, 'title', desc); |
| ic.style.color = color; |
| app(t, ic); |
| } |
| if (borked) { |
| set(t, 'data-steps-failure', 'true'); |
| } else { |
| set(t, 'data-steps-failure', 'false'); |
| } |
| t.style.minWidth = "260px"; |
| app(d, t); |
| lu = "Unknown"; |
| if (lastUpdate > 0) { |
| lu = ""; |
| t = (new Date().getTime() / 1000) - lastUpdate; |
| h = Math.floor(t / 3600); |
| m = Math.floor((t % 3600) / 60); |
| if (h > 0) { |
| lu = h + " hour" + (h === 1 ? '' : 's') + ", "; |
| } |
| lu += m + " minute" + (m === 1 ? '' : 's') + " ago."; |
| } |
| t = mk('td'); |
| t.style.textAlign = 'right'; |
| t.style.color = "#963"; |
| t.style.width = "200px !important"; |
| app(t, txt(lu)); |
| app(d, t); |
| status = mk('td'); |
| status.style.width = "600px !important"; |
| if (lastFailure) { |
| status.style.color = "#843"; |
| app(status, txt(lastFailure)); |
| if (lastException) { |
| app(status, mk('br')); |
| app(status, txt("Exception: " + lastException)); |
| } |
| app(d, status); |
| } else { |
| if (lastUpdate === 0) { |
| app(status, txt("Source hasn't been processed yet...")); |
| } else { |
| if (running) { |
| app(status, txt(running)); |
| } else { |
| app(status, txt("No errors detected.")); |
| } |
| } |
| app(d, status); |
| } |
| act = mk('td'); |
| dbtn = mk('button'); |
| set(dbtn, 'class', 'btn btn-danger'); |
| set(dbtn, 'onclick', 'deletesource("' + source.sourceID + '");'); |
| dbtn.style.padding = "2px"; |
| app(dbtn, txt("Delete")); |
| app(act, dbtn); |
| app(d, act); |
| tbody.inject(d); |
| } |
| for (t in sourceTypes) { |
| el = sourceTypes[t]; |
| div = new HTML('div', { |
| "class": "sourceTypeIcon", |
| onclick: "showType('" + t + "');" |
| }); |
| el.btn = div; |
| img = new HTML('img', { |
| src: "images/sourcetypes/" + t + ".png", |
| style: { |
| width: "32px", |
| margin: "2px", |
| cursor: "pointer" |
| }, |
| title: t |
| }); |
| div.inject(img); |
| div.inject(" " + t + ": " + el.count); |
| slist.inject(div); |
| } |
| } |
| state.widget.inject(slist, true); |
| state.widget.inject(vlist); |
| retval = mk('div'); |
| set(retval, 'id', 'retval'); |
| state.widget.inject(retval); |
| return showType(true); |
| }; |
| |
| showType = function(t) { |
| var el, results, st; |
| results = []; |
| for (st in sourceTypes) { |
| el = sourceTypes[st]; |
| if (st === t || t === true) { |
| t = "blargh"; |
| el.btn.className = "sourceTypeIcon selected"; |
| results.push(el.main.style.display = "block"); |
| } else { |
| el.btn.className = "sourceTypeIcon"; |
| results.push(el.main.style.display = "none"); |
| } |
| } |
| return results; |
| }; |
| |
| addSourceType = function(t) { |
| var el, results, st; |
| results = []; |
| for (st in aSourceTypes) { |
| el = aSourceTypes[st]; |
| if (st === t) { |
| results.push(el.style.display = "block"); |
| } else { |
| results.push(el.style.display = "none"); |
| } |
| } |
| return results; |
| }; |
| |
| aSourceTypes = {}; |
| |
| st = {}; |
| |
| sourceadd = function(json, state) { |
| var abit, btn, div, el, k, lbl, len, obj, opt, q, ref, results, type, v; |
| div = new HTML('div', { |
| style: { |
| position: "relative" |
| } |
| }); |
| div.inject(new HTML('h3', {}, "Source type:")); |
| st = json; |
| for (type in json) { |
| el = json[type]; |
| aSourceTypes[type] = new HTML('form', { |
| style: { |
| float: "left", |
| background: "#FFE", |
| border: "2px solid #333", |
| margin: "20px", |
| borderRadius: "10px", |
| padding: "20px", |
| display: "none" |
| } |
| }); |
| obj = aSourceTypes[type]; |
| obj.inject(new HTML("h4", {}, el.title + ":")); |
| opt = new HTML('input', { |
| onclick: "addSourceType('" + type + "');", |
| type: "radio", |
| id: "type_" + type, |
| name: "type", |
| style: { |
| width: "16px", |
| height: "16px" |
| } |
| }); |
| lbl = new HTML('label', { |
| 'for': "type_" + type, |
| style: { |
| marginRight: "20px" |
| } |
| }, [ |
| new HTML('img', { |
| src: "images/sourcetypes/" + type + ".png", |
| width: "32", |
| height: "32" |
| }), type |
| ]); |
| div.inject(opt); |
| div.inject(lbl); |
| obj.inject(new HTML('p', {}, el.description || "")); |
| obj.inject(keyValueForm('textarea', 'source', 'Source URL/ID:', "For example: " + el.example + ". You can add multiple sources, one per line.")); |
| if (el.optauth) { |
| obj.inject((el.authrequired ? "Required" : "Optional") + " authentication options:"); |
| ref = el.optauth; |
| for (q = 0, len = ref.length; q < len; q++) { |
| abit = ref[q]; |
| obj.inject(keyValueForm('text', "" + abit, abit)); |
| } |
| } |
| btn = new HTML('input', { |
| "class": "btn btn-primary btn-block", |
| type: "button", |
| onclick: "addSources('" + type + "', this.form);", |
| value: "Add source(s)" |
| }); |
| obj.inject(btn); |
| } |
| state.widget.inject(div, true); |
| results = []; |
| for (k in aSourceTypes) { |
| v = aSourceTypes[k]; |
| results.push(state.widget.inject(v)); |
| } |
| return results; |
| }; |
| |
| sourceAdded = function(json, state) { |
| return window.setTimeout(function() { |
| return location.reload(); |
| }, 1000); |
| }; |
| |
| addSources = function(type, form) { |
| var el, js, jsa, len, len1, lineNo, q, re, ref, ref1, source, u; |
| jsa = []; |
| lineNo = 0; |
| re = new RegExp(st[type].regex); |
| ref = form.elements.namedItem('source').value.split(/\r?\n/); |
| for (q = 0, len = ref.length; q < len; q++) { |
| source = ref[q]; |
| lineNo++; |
| if (!source.match(re)) { |
| alert("Source on line " + lineNo + " does not match the required source regex " + st[type].regex + "!"); |
| return false; |
| } |
| js = { |
| type: type, |
| sourceURL: source |
| }; |
| ref1 = form.elements; |
| for (u = 0, len1 = ref1.length; u < len1; u++) { |
| el = ref1[u]; |
| if (el.name.length > 0 && el.name !== 'source') { |
| js[el.name] = el.value; |
| } |
| } |
| jsa.push(js); |
| } |
| return put('sources', { |
| sources: jsa |
| }, {}, sourceAdded); |
| }; |
| |
| WarbleLoginCallback = function(json, state) { |
| var m; |
| userAccount = json; |
| m = location.href.match(/\?redirect=(.+)$/); |
| if (m && !m[1].match(/:/)) { |
| return location.href = m[1]; |
| } else { |
| return location.href = "/dashboard.html?page=frontpage"; |
| } |
| }; |
| |
| WarbleLogin = function(user, password) { |
| put("session", { |
| username: user, |
| password: password |
| }, null, WarbleLoginCallback); |
| return false; |
| }; |
| |
| signout = function() { |
| return xdelete('session', {}, {}, function() { |
| return location.href = 'login.html'; |
| }); |
| }; |
| |
| clientTypes = {}; |
| |
| showClientType = function(t) { |
| var el, results; |
| results = []; |
| for (st in clientTypes) { |
| el = clientTypes[st]; |
| if (st === t || t === true) { |
| t = "blargh"; |
| el.btn.className = "sourceTypeIcon selected"; |
| results.push(el.main.style.display = "block"); |
| } else { |
| el.btn.className = "sourceTypeIcon"; |
| results.push(el.main.style.display = "none"); |
| } |
| } |
| return results; |
| }; |
| |
| makeClientType = function(main, t) { |
| var el, len, obj, q, ref, tbl, tbody, td, thead, tr; |
| if (!clientTypes[t]) { |
| obj = new HTML('div', { |
| id: "client_" + t, |
| style: { |
| display: "block" |
| } |
| }); |
| tbl = mk('table'); |
| set(tbl, 'class', 'table table-striped'); |
| thead = mk('thead'); |
| tr = mk('tr'); |
| ref = ['ID', 'IP', 'Hostname / Fingerprint', 'Location', 'Verified', 'Enabled', 'Last Ping', 'Actions']; |
| for (q = 0, len = ref.length; q < len; q++) { |
| el = ref[q]; |
| td = mk('th'); |
| if (el.match(/Hostname/)) { |
| td.style.width = "200px"; |
| } |
| if (el.match(/Location/)) { |
| td.style.minWidth = "300px"; |
| } |
| if (el.match(/Actions/)) { |
| td.style.minWidth = "240px"; |
| } |
| app(td, txt(el)); |
| app(tr, td); |
| } |
| app(thead, tr); |
| app(tbl, thead); |
| tbody = new HTML('tbody'); |
| app(tbl, tbody); |
| obj.inject(tbl); |
| main.inject(obj); |
| clientTypes[t] = { |
| main: obj, |
| div: tbody, |
| count: 0 |
| }; |
| } |
| return clientTypes[t]; |
| }; |
| |
| modifyNode = function(id, stats) { |
| stats['id'] = id; |
| return post('node/modify', stats, {}, location.reload()); |
| }; |
| |
| deleteNode = function(id, stats) { |
| if (confirm('Are you sure you wish to delete this node?')) { |
| return xdelete('node/modify', { |
| id: id |
| }, {}, location.reload()); |
| } |
| }; |
| |
| nodeVal = function(id, obj, t) { |
| var ip, loc; |
| if (!document.getElementById("node_" + t + "_tmp_" + id)) { |
| loc = obj.innerText; |
| obj.innerHTML = ""; |
| ip = new HTML('input', { |
| style: { |
| color: '#333', |
| width: '320px', |
| height: '24px', |
| padding: '0px' |
| }, |
| data: loc, |
| id: "node_" + t + "_tmp_" + id, |
| type: 'text', |
| onkeydown: "saveNodeValue(" + id + ", this, event, '" + t + "');", |
| onblur: "savedNodeValue({}, {id: " + id + ", type: '" + t + "', " + t + ": this.getAttribute('data')});" |
| }); |
| ip.value = loc; |
| app(obj, ip); |
| return ip.focus(); |
| } |
| }; |
| |
| saveNodeValue = function(id, obj, e, t) { |
| var js, jsx, nval; |
| if (e.key === 'Enter') { |
| nval = obj.value; |
| js = { |
| id: id |
| }; |
| jsx = { |
| id: id, |
| type: t |
| }; |
| js[t] = nval; |
| jsx[t] = nval; |
| return post('node/modify', js, jsx, savedNodeValue); |
| } else if (e.key === 'Escape') { |
| js = { |
| id: id |
| }; |
| jsx = { |
| id: id, |
| type: t |
| }; |
| js[t] = obj.getAttribute('data'); |
| jsx[t] = obj.getAttribute('data'); |
| return savedNodeValue(js, jsx); |
| } |
| }; |
| |
| savedNodeValue = function(json, state) { |
| var obj; |
| obj = document.getElementById("node_" + state.type + "_" + state.id); |
| obj.innerHTML = ""; |
| return app(obj, txt(state[state.type])); |
| }; |
| |
| nodeStatusSort = (function(_this) { |
| return function(a, b) { |
| if (a.enabled && !b.enabled) { |
| return -1; |
| } |
| if (b.enabled && !a.enabled) { |
| return 1; |
| } |
| if (a.verified && !b.verified) { |
| return -1; |
| } |
| if (b.verified && !a.verified) { |
| return 1; |
| } |
| return a.hostname.localeCompare(b.hostname); |
| }; |
| })(this); |
| |
| clientlist = function(json, state) { |
| var banner, btn, card, d, hn, len, line, lline, lp, q, retval, rline, slist, source, sources, vlist, vrf; |
| slist = mk('div'); |
| vlist = new HTML('div'); |
| if (json.nodes) { |
| sources = json.nodes; |
| sources = sources.sort ? sources : []; |
| sources.sort(nodeStatusSort); |
| for (q = 0, len = sources.length; q < len; q++) { |
| source = sources[q]; |
| card = new HTML('div', { |
| "class": 'clientcard' |
| }); |
| banner = new HTML('div', { |
| "class": 'banner' |
| }); |
| rline = new HTML('div', { |
| style: { |
| float: 'right', |
| width: '300px', |
| textAlign: 'center' |
| } |
| }); |
| lline = new HTML('div', { |
| style: { |
| float: 'left', |
| width: '500px', |
| textAlign: 'center' |
| } |
| }); |
| hn = new HTML('span', { |
| title: 'Click to edit', |
| id: "node_hostname_" + source.id, |
| onclick: "nodeVal(" + source.id + ", this, 'hostname');" |
| }, txt(source.hostname || "(unknown)")); |
| lline.inject(hn); |
| vrf = []; |
| if (!source.verified) { |
| card.setAttribute('class', 'clientcard orange'); |
| vrf = [ |
| 'Unverified Node', new HTML('button', { |
| "class": 'btn btn-sm btn-primary', |
| onclick: "modifyNode(" + source.id + ", {verified: true, enabled: true});" |
| }, "Verify + Enable") |
| ]; |
| rline.inject(vrf); |
| btn = new HTML('button', { |
| title: 'Delete node', |
| "class": 'btn btn-square btn-danger', |
| style: { |
| position: 'relative', |
| float: 'right', |
| display: 'inline-block' |
| }, |
| onclick: "deleteNode(" + source.id + ");" |
| }, new HTML('i', { |
| "class": 'fa fa-trash' |
| }, '')); |
| rline.inject(btn); |
| } |
| if (source.verified) { |
| vrf = []; |
| card.setAttribute('class', 'clientcard green'); |
| if (source.enabled) { |
| vrf = [ |
| 'Active', new HTML('button', { |
| "class": 'btn btn-sm btn-warning', |
| onclick: "modifyNode(" + source.id + ", {enabled: false});" |
| }, "Disable") |
| ]; |
| } else { |
| card.setAttribute('class', 'clientcard grey'); |
| vrf = [ |
| 'Disabled', new HTML('button', { |
| "class": 'btn btn-sm btn-primary', |
| onclick: "modifyNode(" + source.id + ", {enabled: true});" |
| }, "Re-enable") |
| ]; |
| } |
| rline.inject(vrf); |
| btn = new HTML('button', { |
| title: 'Delete node', |
| "class": 'btn btn-square btn-danger', |
| style: { |
| position: 'relative', |
| float: 'right', |
| display: 'inline-block' |
| }, |
| onclick: "deleteNode(" + source.id + ");" |
| }, new HTML('i', { |
| "class": 'fa fa-trash' |
| }, '')); |
| rline.inject(btn); |
| } |
| banner.inject(lline); |
| banner.inject(rline); |
| card.inject(banner); |
| vlist.inject(card); |
| d = new HTML('p'); |
| card.inject(d); |
| line = new HTML('div', { |
| "class": 'clientcardline' |
| }); |
| line.inject([new HTML('b', {}, "Node ID: "), txt(source.id)]); |
| d.inject(line); |
| line = new HTML('div', { |
| "class": 'clientcardline' |
| }); |
| line.inject([new HTML('b', {}, "Node IP: "), txt(source.ip)]); |
| d.inject(line); |
| line = new HTML('div', { |
| "class": 'clientcardline' |
| }); |
| line.inject([new HTML('b', {}, "Fingerprint: "), new HTML('kbd', {}, source.fingerprint)]); |
| d.inject(line); |
| line = new HTML('div', { |
| "class": 'clientcardline' |
| }); |
| line.inject([ |
| new HTML('b', {}, "Location: "), new HTML('span', { |
| title: 'Click to edit', |
| id: "node_location_" + source.id, |
| onclick: "nodeVal(" + source.id + ", this, 'location');" |
| }, txt(source.location || "(unknown)")) |
| ]); |
| d.inject(line); |
| line = new HTML('div', { |
| "class": 'clientcardline' |
| }); |
| line.inject([ |
| new HTML('b', {}, "Notes: "), new HTML('span', { |
| title: 'Click to edit', |
| id: "node_description_" + source.id, |
| onclick: "nodeVal(" + source.id + ", this, 'description');" |
| }, txt(source.description || "(none)")) |
| ]); |
| d.inject(line); |
| line = new HTML('div', { |
| "class": 'clientcardline' |
| }); |
| lp = new Date(source.lastping * 1000.0); |
| line.inject([new HTML('b', {}, "Last Active: "), txt(moment(lp).fromNow() + " (" + lp.ISOBare() + ")")]); |
| d.inject(line); |
| } |
| } |
| state.widget.inject(slist, true); |
| state.widget.inject(vlist); |
| retval = mk('div'); |
| set(retval, 'id', 'retval'); |
| state.widget.inject(retval); |
| return showType(true); |
| }; |
| |
| orgadmin = function(json, state) { |
| var btn, div, h2, h4, id, inp, obj, pdiv, title; |
| if (globArgs.org && json.admin[globArgs.org]) { |
| pdiv = document.createElement('div'); |
| id = globArgs.org; |
| title = json.admin[id]; |
| h2 = mk('h2'); |
| app(h2, txt("Editing: " + title)); |
| app(pdiv, h2); |
| obj = mk('form'); |
| h4 = mk('h4'); |
| app(h4, txt("Invite a new user to this org:")); |
| app(obj, h4); |
| div = mk('div'); |
| app(div, txt("Username (email): ")); |
| inp = mk('input'); |
| set(inp, 'type', 'text'); |
| set(inp, 'name', 'who'); |
| inp.style.width = "200px"; |
| app(div, inp); |
| app(obj, div); |
| div = mk('div'); |
| app(div, txt("Make administrator: ")); |
| inp = mk('input'); |
| set(inp, 'type', 'checkbox'); |
| set(inp, 'name', 'admin'); |
| set(inp, 'value', 'true'); |
| app(div, inp); |
| app(obj, div); |
| btn = mk('input'); |
| set(btn, 'type', 'button'); |
| set(btn, 'onclick', 'addorguser(this.form)'); |
| set(btn, 'value', "Add user"); |
| app(obj, btn); |
| app(pdiv, obj); |
| obj = mk('form'); |
| h4 = mk('h4'); |
| app(h4, txt("Remove a user from the org:")); |
| app(obj, h4); |
| div = mk('div'); |
| app(div, txt("Username (email): ")); |
| inp = mk('input'); |
| set(inp, 'type', 'text'); |
| set(inp, 'name', 'who'); |
| inp.style.width = "200px"; |
| app(div, inp); |
| app(obj, div); |
| div = mk('div'); |
| app(div, txt("Just remove admin privs (if any): ")); |
| inp = mk('input'); |
| set(inp, 'type', 'checkbox'); |
| set(inp, 'name', 'admin'); |
| set(inp, 'value', 'true'); |
| app(div, inp); |
| app(obj, div); |
| btn = mk('input'); |
| set(btn, 'type', 'button'); |
| set(btn, 'onclick', 'remorguser(this.form)'); |
| set(btn, 'value', "Remove user"); |
| app(obj, btn); |
| app(pdiv, obj); |
| return state.widget.inject(pdiv, true); |
| } else { |
| return state.widget.inject(txt("You are not an admin of this organisation!")); |
| } |
| }; |
| |
| addorguser = function(form) { |
| var i, js, k, q, ref, v; |
| js = { |
| action: 'add', |
| org: globArgs.org |
| }; |
| for (i = q = 0, ref = form.length - 1; 0 <= ref ? q <= ref : q >= ref; i = 0 <= ref ? ++q : --q) { |
| k = form[i].name; |
| v = form[i].value; |
| if (k === 'who') { |
| form[i].value = ""; |
| } |
| if (k === 'admin') { |
| v = form[i].checked ? 'true' : 'false'; |
| } |
| if (k === 'who' || k === 'admin') { |
| js[k] = v; |
| } |
| } |
| return postJSON("admin-org", js, null, function(a) { |
| return alert("User added!"); |
| }); |
| }; |
| |
| remorguser = function(form) { |
| var i, js, k, q, ref, v; |
| js = { |
| action: 'remove', |
| org: globArgs.org |
| }; |
| for (i = q = 0, ref = form.length - 1; 0 <= ref ? q <= ref : q >= ref; i = 0 <= ref ? ++q : --q) { |
| k = form[i].name; |
| v = form[i].value; |
| if (k === 'who') { |
| form[i].value = ""; |
| } |
| if (k === 'admin') { |
| v = form[i].checked ? 'true' : 'false'; |
| } |
| if (k === 'who' || k === 'admin') { |
| js[k] = v; |
| } |
| } |
| return postJSON("admin-org", js, null, function(a) { |
| return alert("User removed!"); |
| }); |
| }; |
| |
| tagList = {}; |
| |
| affiliation = function(json, state) { |
| var a, btn, gdiv, group, groupname, groups, h3, h4, len, len1, members, ngroups, obj, p, pdiv, person, q, ref, ref1, u; |
| obj = mk('div'); |
| groups = []; |
| ref = json.groups; |
| for (group in ref) { |
| members = ref[group]; |
| groups.push(group); |
| } |
| groups.sort((function(_this) { |
| return function(a, b) { |
| return json.groups[b].length - json.groups[a].length; |
| }; |
| })(this)); |
| h3 = mk('h3'); |
| ngroups = groups.length; |
| if (indexOf.call(groups, '_untagged') >= 0) { |
| ngroups--; |
| } |
| app(h3, txt("Found " + ngroups + " organisations/companies:")); |
| app(obj, h3); |
| btn = mk('input'); |
| set(btn, 'type', 'button'); |
| set(btn, 'class', 'btn btn-info'); |
| set(btn, 'value', 'Group wizard'); |
| set(btn, 'widget', state.widget.id); |
| btn.addEventListener("click", function() { |
| var w; |
| w = findWidget(this.getAttribute('widget')); |
| w.args.eargs = { |
| autogroup: true |
| }; |
| w.callback = affiliationWizard; |
| return w.reload(); |
| }); |
| p = mk('p'); |
| app(p, txt("You may use the ")); |
| app(p, btn); |
| app(p, txt(" to quickly group people into companies etc.")); |
| app(obj, p); |
| p = mk('p'); |
| app(p, txt("NOTE: For certain charts (evolutions etc), only the 30 largest groups will be shown due to computational optimisations.")); |
| app(obj, p); |
| for (q = 0, len = groups.length; q < len; q++) { |
| group = groups[q]; |
| groupname = group.split(/\./)[0].replace(/^([a-z])/, (function(_this) { |
| return function(a) { |
| return a.toUpperCase(); |
| }; |
| })(this)); |
| if (group === '_untagged') { |
| groupname = "People with no current affiliation"; |
| } |
| h4 = mk('h4'); |
| app(h4, txt(groupname + ": " + json.groups[group].length + " members")); |
| h4.style.fontSize = "14pt"; |
| h4.setAttribute("onclick", "var a = get('people_" + group + "'); a.style.display = (a.style.display == 'block') ? 'none' : 'block';"); |
| h4.style.display = "inline-block"; |
| h4.style.cursor = 'se-resize'; |
| app(obj, h4); |
| app(obj, mk('br')); |
| gdiv = mk('div'); |
| gdiv.setAttribute("id", "people_" + group); |
| gdiv.style.border = "1px solid #999"; |
| gdiv.style.display = "none"; |
| ref1 = json.groups[group]; |
| for (u = 0, len1 = ref1.length; u < len1; u++) { |
| person = ref1[u]; |
| pdiv = mk('div'); |
| set(pdiv, 'id', 'tag_' + group + '_' + person.id); |
| app(pdiv, txt(person.name + " - <" + person.email + "> - ")); |
| a = mk('a'); |
| set(a, 'href', 'javascript:void(0);'); |
| set(a, 'onclick', "this.parentNode.parentNode.removeChild(this.parentNode); js = { untag: {} }; js.untag['" + person.id + "'] = '" + group + "'; postJSON('/api/2/affiliations', js, null, null, null);"); |
| app(a, txt("Remove from group")); |
| app(pdiv, a); |
| app(gdiv, pdiv); |
| } |
| app(obj, gdiv); |
| } |
| return state.widget.inject(obj, true); |
| }; |
| |
| affiliationWizard = function(json, state) { |
| var a, btn, chk, gdiv, group, groupname, groups, h3, h4, id, label, len, len1, members, obj, p, person, q, ref, ref1, sp, u; |
| obj = mk('div'); |
| groups = []; |
| ref = json.groups; |
| for (group in ref) { |
| members = ref[group]; |
| groups.push(group); |
| } |
| groups.sort((function(_this) { |
| return function(a, b) { |
| return json.groups[b].length - json.groups[a].length; |
| }; |
| })(this)); |
| h3 = mk('h3'); |
| app(h3, txt("Found " + groups.length + " possible organisations/companies:")); |
| app(obj, h3); |
| p = mk('p'); |
| app(p, txt("Select a group or individuals within it to tag them as belonging to that group.")); |
| app(obj, p); |
| for (q = 0, len = groups.length; q < len; q++) { |
| group = groups[q]; |
| groupname = group.split(/\./)[0].replace(/^([a-z])/, (function(_this) { |
| return function(a) { |
| return a.toUpperCase(); |
| }; |
| })(this)); |
| h4 = mk('h4'); |
| app(h4, txt(groupname + ": " + json.groups[group].length + " members")); |
| h4.style.fontSize = "14pt"; |
| h4.setAttribute("onclick", "var a = get('people_" + group + "'); a.style.display = (a.style.display == 'block') ? 'none' : 'block';"); |
| id = Math.floor(Math.random() * 987654321).toString(16); |
| chk = document.createElement('input'); |
| chk.setAttribute("type", "checkbox"); |
| chk.setAttribute("id", group); |
| chk.style.marginLeft = '10px'; |
| chk.style.color = "#090"; |
| chk.style.fontSize = "16pt"; |
| chk.setAttribute("class", "f"); |
| chk.addEventListener("change", function() { |
| var len1, person, ref1, results, u; |
| group = this.getAttribute('id'); |
| ref1 = json.groups[group]; |
| results = []; |
| for (u = 0, len1 = ref1.length; u < len1; u++) { |
| person = ref1[u]; |
| chk = get('tag_' + person.id); |
| results.push(chk.checked = this.checked); |
| } |
| return results; |
| }); |
| app(obj, chk); |
| h4.style.display = "inline-block"; |
| h4.style.cursor = 'se-resize'; |
| app(obj, h4); |
| app(obj, mk('br')); |
| gdiv = mk('div'); |
| gdiv.setAttribute("id", "people_" + group); |
| gdiv.style.border = "1px solid #999"; |
| gdiv.style.display = "none"; |
| ref1 = json.groups[group]; |
| for (u = 0, len1 = ref1.length; u < len1; u++) { |
| person = ref1[u]; |
| chk = document.createElement('input'); |
| chk.setAttribute("type", "checkbox"); |
| chk.setAttribute("id", 'tag_' + person.id); |
| chk.setAttribute("pid", person.id); |
| chk.setAttribute("value", group); |
| chk.style.marginLeft = '10px'; |
| chk.style.color = "#369"; |
| chk.style.fontSize = "10pt"; |
| label = document.createElement('label'); |
| label.setAttribute("for", 'tag_' + person.id); |
| label.setAttribute("title", "Check this box to tag this person as affiliated with " + groupname); |
| chk.setAttribute("title", "Check this box to tag this person as affiliated with " + groupname); |
| label.style.paddingLeft = '5px'; |
| label.appendChild(document.createTextNode(person.name + " - <" + person.email + ">")); |
| app(gdiv, chk); |
| app(gdiv, label); |
| a = mk('a'); |
| set(a, 'href', 'javascript:void(affiliate("' + person.id + '"));'); |
| app(a, txt("Set a tag")); |
| app(gdiv, txt(" - ")); |
| app(gdiv, a); |
| sp = mk('span'); |
| set(sp, 'id', 'tags_' + person.id); |
| app(gdiv, sp); |
| app(gdiv, mk('br')); |
| } |
| app(obj, gdiv); |
| } |
| btn = mk('input'); |
| set(btn, 'type', 'button'); |
| set(btn, 'class', 'btn btn-info'); |
| set(btn, 'value', 'Save changes'); |
| set(btn, 'widget', state.widget.id); |
| btn.addEventListener("click", function() { |
| var w; |
| w = findWidget(this.getAttribute('widget')); |
| tagList = {}; |
| $("[type=checkbox]").each(function() { |
| var pid, val; |
| pid = $(this).attr('pid'); |
| val = $(this).attr('value'); |
| if (pid && pid.length > 0 && ($(this).attr('checked') || $(this).is(':checked'))) { |
| return tagList[pid] = val; |
| } |
| }); |
| w.args.eargs = { |
| tag: tagList |
| }; |
| w.callback = affiliation; |
| return w.reload(); |
| }); |
| app(obj, btn); |
| return state.widget.inject(obj, true); |
| }; |
| |
| affiliate = function(hash) { |
| var tag, tags, tr; |
| tag = window.prompt("Please enter the tag with which you wish to associate this source, or type nothing to untag."); |
| if (tag === "") { |
| tag = null; |
| } |
| tr = get('tags_' + hash); |
| tags = {}; |
| tags[hash] = tag; |
| if (tag) { |
| postJSON('affiliations', { |
| tag: tags |
| }, null, null); |
| return app(tr, txt("(Tagged as: " + tag + ") ")); |
| } |
| }; |
| |
| altemail = function(hash) { |
| var tag, tags, tr; |
| tag = window.prompt("Please enter the alt email with which you wish to associate this source, or type nothing to clear alts."); |
| if (tag === "") { |
| tag = null; |
| } |
| tr = get('tags_' + hash); |
| tags = {}; |
| tags[hash] = tag; |
| if (tag) { |
| postJSON('affiliations', { |
| altemail: tags |
| }, null, null); |
| return app(tr, txt("(Affiliated as: " + tag + ") ")); |
| } |
| }; |
| |
| bio = function(json, state) { |
| var a, a2, bioInner, bioOuter, egroups, firstauthor, firstcommit, firstemail, groups, len, len1, namecard, obj, q, ref, ref1, sp, tag, u; |
| obj = document.createElement('div'); |
| if (json.found) { |
| firstcommit = "Never"; |
| if (json.bio.firstCommit) { |
| firstcommit = new Date(json.bio.firstCommit * 1000).toDateString(); |
| } |
| firstauthor = "Never"; |
| if (json.bio.firstAuthor) { |
| firstauthor = new Date(json.bio.firstAuthor * 1000).toDateString(); |
| } |
| firstemail = "Never"; |
| if (json.bio.firstEmail) { |
| firstemail = new Date(json.bio.firstEmail * 1000).toDateString(); |
| } |
| bioOuter = new HTML('div', { |
| "class": 'media-event' |
| }); |
| bioOuter.inject(new HTML('a', { |
| "class": 'pull-left bio-image' |
| }, new HTML('img', { |
| style: "width: 128px; height: 128px;", |
| src: 'https://secure.gravatar.com/avatar/' + json.bio.gravatar + '.png?d=identicon&size=128' |
| }))); |
| bioInner = new HTML('div', { |
| "class": 'media-body bio-profile' |
| }); |
| bioInner.inject(new HTML('h2', {}, json.bio.name)); |
| bioInner.inject(new HTML('h3', {}, json.bio.email)); |
| bioInner.inject(new HTML('hr', {})); |
| bioInner.inject(new HTML('div', { |
| "class": 'bio-fact' |
| }, [new HTML('strong', {}, 'First code commit'), new HTML('br'), new HTML('span', {}, firstcommit)])); |
| bioInner.inject(new HTML('div', { |
| "class": 'bio-fact' |
| }, [new HTML('strong', {}, 'First code authorship'), new HTML('br'), new HTML('span', {}, firstauthor)])); |
| bioInner.inject(new HTML('div', { |
| "class": 'bio-fact' |
| }, [new HTML('strong', {}, 'First email'), new HTML('br'), new HTML('span', {}, firstemail)])); |
| bioInner.inject(new HTML('div', { |
| "class": 'bio-fact' |
| }, [new HTML('strong', {}, 'Commits'), new HTML('br'), new HTML('span', {}, json.bio.commits.pretty())])); |
| bioInner.inject(new HTML('div', { |
| "class": 'bio-fact' |
| }, [new HTML('strong', {}, 'Emails'), new HTML('br'), new HTML('span', {}, json.bio.emails.pretty())])); |
| bioOuter.inject(bioInner); |
| obj.appendChild(bioOuter); |
| namecard = mk('h2'); |
| groups = []; |
| if (json.bio.tags) { |
| ref = json.bio.tags; |
| for (q = 0, len = ref.length; q < len; q++) { |
| tag = ref[q]; |
| if (tag !== '_untagged') { |
| groups.push(tag); |
| } |
| } |
| } |
| if (groups.length > 0) { |
| namecard.appendChild(mk('br')); |
| namecard.appendChild(txt("Part of: " + groups.join(", "))); |
| } |
| a = mk('a'); |
| set(a, 'href', 'javascript:void(affiliate("' + json.bio.id + '"));'); |
| app(a, txt("Set a tag")); |
| egroups = []; |
| if (json.bio.alts && json.bio.alts.length) { |
| ref1 = json.bio.alts; |
| for (u = 0, len1 = ref1.length; u < len1; u++) { |
| tag = ref1[u]; |
| egroups.push(tag); |
| } |
| } |
| if (egroups.length > 0) { |
| namecard.appendChild(mk('br')); |
| namecard.appendChild(txt("Also known as: " + egroups.join(", "))); |
| } |
| a2 = mk('a'); |
| a2.style.marginLeft = "8px"; |
| set(a2, 'href', 'javascript:void(altemail("' + json.bio.id + '"));'); |
| app(a2, txt("Add alt email")); |
| sp = mk('span'); |
| set(sp, 'id', 'tags_' + json.bio.id); |
| app(obj, namecard); |
| app(obj, a); |
| app(obj, a2); |
| app(obj, sp); |
| } else { |
| obj.innerHTML = "Person not found :/"; |
| } |
| return state.widget.inject(obj, true); |
| }; |
| |
| widgetCache = []; |
| |
| findWidget = function(id) { |
| var len, q, w; |
| for (q = 0, len = widgetCache.length; q < len; q++) { |
| w = widgetCache[q]; |
| if (w.id === id) { |
| return w; |
| } |
| } |
| return null; |
| }; |
| |
| toFullscreen = function(id) { |
| var CW, FSA, dobrk, ic, len, node, nxt, obj, q, ref, w; |
| obj = get(id); |
| FSA = get('FS_' + id); |
| FSA.innerHTML = "Pop back"; |
| FSA.setAttribute("onclick", "toNormal('" + id + "');"); |
| CW = get('CW_' + id); |
| CW.setAttribute("onclick", "toNormal('" + id + "');"); |
| w = findWidget(id); |
| w.parent = obj.parentNode; |
| w.sibling = null; |
| nxt = null; |
| dobrk = false; |
| ref = w.parent.childNodes; |
| for (q = 0, len = ref.length; q < len; q++) { |
| node = ref[q]; |
| if (dobrk) { |
| nxt = node; |
| break; |
| } else if (node === obj) { |
| dobrk = true; |
| } |
| } |
| w.sibling = nxt; |
| ic = get('innercontents'); |
| app(ic, obj); |
| w.oldStyle = JSON.stringify(obj.style); |
| obj.style.width = "100%"; |
| obj.style.height = "90%"; |
| obj.style.background = "#EEE"; |
| obj.style.position = "absolute"; |
| obj.style.top = "10px"; |
| obj.style.left = "10px"; |
| obj.style.zIndex = "2000"; |
| w.fullscreen = true; |
| w.reload(true); |
| $("html, body").animate({ |
| scrollTop: 0 |
| }, "fast"); |
| return true; |
| }; |
| |
| toNormal = function(id) { |
| var CW, FSA, obj, w; |
| obj = get(id); |
| w = findWidget(id); |
| FSA = get('FS_' + id); |
| FSA.innerHTML = "Fullscreen"; |
| FSA.setAttribute("onclick", "toFullscreen('" + id + "');"); |
| CW = get('CW_' + id); |
| CW.setAttribute("onclick", "findWidget('" + id + "').kill();"); |
| if (w.sibling) { |
| w.parent.insertBefore(obj, w.sibling); |
| } else { |
| app(w.parent, obj); |
| } |
| obj.style = JSON.parse(w.oldStyle); |
| w.fullscreen = false; |
| w.reload(true); |
| return true; |
| }; |
| |
| updateWidgets = function(type, target, eargs) { |
| var g, gargs, k, len, q, results, v, wargs, widget, wloc; |
| wargs = window.location.search; |
| wloc = ""; |
| for (k in eargs) { |
| v = eargs[k]; |
| globArgs[k] = v; |
| g = []; |
| for (k in globArgs) { |
| v = globArgs[k]; |
| if (k && v) { |
| g.push(k + '=' + v); |
| } |
| } |
| gargs = "?" + g.join("&"); |
| wloc = window.location.pathname + gargs; |
| } |
| if (wargs !== gargs) { |
| window.history.pushState({}, "", wloc); |
| console.log("pushed state " + wloc); |
| window.onpopstate = function(event) { |
| return loadPageWidgets(); |
| }; |
| } |
| results = []; |
| for (q = 0, len = widgetCache.length; q < len; q++) { |
| widget = widgetCache[q]; |
| if (type === widget.args.type) { |
| widget.args.target = target && target || widget.args.target; |
| if (eargs) { |
| widget.args.eargs = widget.args.eargs && widget.args.eargs || {}; |
| for (k in eargs) { |
| v = eargs[k]; |
| widget.args.eargs[k] = v; |
| if (!v) { |
| delete widget.args.eargs[k]; |
| } |
| } |
| } |
| switch (widget.args.type) { |
| case 'donut': |
| results.push(widget.load(donut)); |
| break; |
| case 'gauge': |
| results.push(widget.load(gauge)); |
| break; |
| case 'radar': |
| results.push(widget.load(radar)); |
| break; |
| case 'paragraph': |
| results.push(widget.load(paragraph)); |
| break; |
| case 'line': |
| results.push(widget.load(linechart)); |
| break; |
| case 'top5': |
| results.push(widget.load(top5)); |
| break; |
| case 'factors': |
| results.push(widget.load(factors)); |
| break; |
| case 'trends': |
| results.push(widget.load(trend)); |
| break; |
| case 'preferences': |
| results.push(widget.load(preferences)); |
| break; |
| case 'messages': |
| results.push(widget.load(messages)); |
| break; |
| case 'widget': |
| results.push(widget.load(publisher)); |
| break; |
| case 'contacts': |
| results.push(fetchPhonebook({ |
| widget: widget, |
| w: w, |
| letter: 'a', |
| project: target |
| })); |
| break; |
| case 'repopicker': |
| results.push(widget.load(explorer)); |
| break; |
| case 'sourcepicker': |
| results.push(widget.load(sourceexplorer)); |
| break; |
| case 'issuepicker': |
| results.push(widget.load(issueexplorer)); |
| break; |
| case 'forumpicker': |
| results.push(widget.load(forumexplorer)); |
| break; |
| case 'viewpicker': |
| results.push(widget.load(viewexplorer)); |
| break; |
| case 'mailpicker': |
| results.push(widget.load(mailexplorer)); |
| break; |
| case 'cipicker': |
| results.push(widget.load(ciexplorer)); |
| break; |
| case 'logpicker': |
| results.push(widget.load(logexplorer)); |
| break; |
| case 'relationship': |
| results.push(widget.load(relationship)); |
| break; |
| case 'treemap': |
| results.push(widget.load(treemap)); |
| break; |
| case 'report': |
| results.push(widget.load(report)); |
| break; |
| case 'mvp': |
| results.push(widget.load(mvp)); |
| break; |
| case 'comstat': |
| results.push(widget.load(comstat)); |
| break; |
| case 'worldmap': |
| results.push(widget.load(worldmap)); |
| break; |
| case 'jsondump': |
| results.push(widget.load(jsondump)); |
| break; |
| default: |
| results.push(void 0); |
| } |
| } else { |
| results.push(void 0); |
| } |
| } |
| return results; |
| }; |
| |
| pubWidget = (function() { |
| function pubWidget(div1, wid, config1) { |
| this.div = div1; |
| this.wid = wid; |
| this.config = config1; |
| this.args = {}; |
| fetch("publish/id=" + this.wid, { |
| config: this.config, |
| widget: this, |
| args: {} |
| }, publisherPublic, null, true); |
| } |
| |
| pubWidget.prototype.inject = function(el, clear) { |
| if (clear) { |
| this.div.innerHTML = ""; |
| } |
| return this.div.appendChild(el); |
| }; |
| |
| return pubWidget; |
| |
| })(); |
| |
| Widget = (function() { |
| function Widget(blocks, args1, pub) { |
| var a, cldiv, i, li, t, tt, ul; |
| this.blocks = blocks; |
| this.args = args1; |
| this.id = Math.floor(Math.random() * 1000000).toString(16); |
| this.div = document.createElement('div'); |
| this.div.setAttribute("id", this.id); |
| this.div.setAttribute("class", "x_panel snoot_widget"); |
| this.div.style.float = 'left'; |
| this.json = {}; |
| if (this.blocks <= 2) { |
| this.div.setAttribute("class", "snoot_widget col-md-2 col-sm-4 col-xs-12"); |
| } else if (this.blocks <= 3) { |
| this.div.setAttribute("class", "snoot_widget col-md-3 col-sm-6 col-xs-12"); |
| } else if (this.blocks <= 4) { |
| this.div.setAttribute("class", "snoot_widget col-md-4 col-sm-8 col-xs-12"); |
| } else if (this.blocks <= 6) { |
| this.div.setAttribute("class", "snoot_widget col-md-6 col-sm-12 col-xs-12"); |
| } else if (this.blocks <= 9) { |
| this.div.setAttribute("class", "snoot_widget col-md-9 col-sm-12 col-xs-12"); |
| } else { |
| this.div.setAttribute("class", "snoot_widget col-md-12 col-sm-12 col-xs-12"); |
| } |
| if (!pub) { |
| t = document.createElement('div'); |
| t.setAttribute("class", "x_title"); |
| tt = document.createElement('h2'); |
| tt.style.fontSize = "17pt"; |
| tt.appendChild(document.createTextNode(this.args.name)); |
| t.appendChild(tt); |
| ul = document.createElement('ul'); |
| ul.setAttribute("class", "nav navbar-right panel_toolbox"); |
| li = document.createElement('li'); |
| this.collapse = document.createElement('a'); |
| this.collapse.setAttribute("class", "collapse-link"); |
| i = document.createElement('i'); |
| i.setAttribute("class", "fa fa-chevron-up"); |
| this.collapse.appendChild(i); |
| li.appendChild(this.collapse); |
| ul.appendChild(li); |
| this.collapse.addEventListener("click", function() { |
| var content, icon, id, panel; |
| id = this.parentNode.parentNode.parentNode.parentNode.getAttribute("id"); |
| panel = $('#' + id); |
| icon = $(this).find('i'); |
| content = panel.find('.x_content'); |
| if (panel.attr('style')) { |
| content.slideToggle(200, function() { |
| return panel.removeAttr('style'); |
| }); |
| } else { |
| content.slideToggle(200); |
| panel.css('height', 'auto'); |
| } |
| return icon.toggleClass('fa-chevron-up fa-chevron-down'); |
| }); |
| li = document.createElement('li'); |
| a = document.createElement('a'); |
| a.setAttribute("class", "close-link"); |
| a.setAttribute("onclick", "findWidget('" + this.id + "').kill();"); |
| i = document.createElement('i'); |
| i.setAttribute("class", "fa fa-close"); |
| a.appendChild(i); |
| a.setAttribute("id", "CW_" + this.id); |
| li.appendChild(a); |
| ul.appendChild(li); |
| t.appendChild(ul); |
| this.div.appendChild(t); |
| cldiv = document.createElement('div'); |
| cldiv.setAttribute("classs", "clearfix"); |
| this.div.appendChild(cldiv); |
| } |
| this.cdiv = document.createElement('div'); |
| this.cdiv.style.width = "100%"; |
| this.cdiv.setAttribute("id", "contents_" + this.id); |
| this.cdiv.setAttribute("class", "x_content"); |
| this.div.appendChild(this.cdiv); |
| widgetCache.push(this); |
| } |
| |
| Widget.prototype.cog = function(size) { |
| var i, idiv; |
| if (size == null) { |
| size = 100; |
| } |
| idiv = document.createElement('div'); |
| idiv.setAttribute("class", "icon"); |
| idiv.setAttribute("style", "text-align: center; vertical-align: middle; height: 500px;"); |
| i = new HTML('div', { |
| "class": "spinwheel" |
| }, new HTML('div', { |
| "class": "spinwheel_md" |
| }, new HTML('div', { |
| "class": "spinwheel_sm" |
| }))); |
| idiv.appendChild(i); |
| idiv.appendChild(document.createElement('br')); |
| idiv.appendChild(document.createTextNode('Loading, hang on tight..!')); |
| this.cdiv.innerHTML = ""; |
| return this.cdiv.appendChild(idiv); |
| }; |
| |
| Widget.prototype.kill = function() { |
| return this.div.parentNode.removeChild(this.div); |
| }; |
| |
| Widget.prototype.inject = function(object, clear) { |
| if (clear) { |
| this.cdiv.innerHTML = ""; |
| this.cdiv.style.textAlign = 'left'; |
| } |
| return this.cdiv.appendChild(object); |
| }; |
| |
| Widget.prototype.snap = function(state) { |
| state.widget.cdiv.innerHTML = "<a style='color: #D44; font-size: 100pt;'><i class='fa fa-warning'></i></a><br/>Oh snap, something went wrong!"; |
| return state.widget.cdiv.style.textAlign = 'center'; |
| }; |
| |
| Widget.prototype.load = function(callback) { |
| var js, url; |
| this.cog(); |
| this.callback = callback; |
| js = this.args.eargs; |
| url = this.args.source; |
| if (this.args.type === 'paragraph') { |
| return this.callback(this.args, { |
| widget: this, |
| eargs: this.args.eargs |
| }); |
| } else { |
| if (this.args.method === 'get') { |
| return fetch(url, { |
| widget: this, |
| eargs: this.args.eargs |
| }, callback, this.snap); |
| } else { |
| return post(url, js, { |
| widget: this, |
| eargs: this.args.eargs |
| }, callback, this.snap); |
| } |
| } |
| }; |
| |
| Widget.prototype.reload = function(fakeit) { |
| var js, url; |
| this.cog(); |
| js = this.args.eargs; |
| url = this.args.source; |
| if (fakeit && this.json) { |
| return this.callback(this.json, { |
| widget: this, |
| eargs: this.args.eargs |
| }); |
| } else { |
| return post(url, js, { |
| widget: this, |
| eargs: this.args.eargs |
| }, this.callback, this.snap); |
| } |
| }; |
| |
| return Widget; |
| |
| })(); |
| |
| rowZ = 100; |
| |
| Row = (function() { |
| function Row() { |
| this.id = Math.floor(Math.random() * 987654321).toString(16); |
| this.div = document.createElement('div'); |
| this.div.setAttribute("class", "row"); |
| this.div.style.zIndex = rowZ; |
| rowZ--; |
| this.div.setAttribute("id", this.id); |
| this.cdiv = document.createElement('div'); |
| this.cdiv.setAttribute("class", "col-md-12"); |
| this.cdiv.setAttribute("id", "contents_" + this.id); |
| this.div.appendChild(this.cdiv); |
| document.getElementById('innercontents').appendChild(this.div); |
| } |
| |
| Row.prototype.inject = function(object, clear) { |
| if (clear) { |
| this.cdiv.innerHTML = ""; |
| } |
| if (object instanceof Widget) { |
| return this.cdiv.appendChild(object.div); |
| } else { |
| return this.cdiv.appendChild(object); |
| } |
| }; |
| |
| return Row; |
| |
| })(); |
| |
| comShow = function(t) { |
| var len, q, row, rows; |
| rows = document.getElementsByTagName("tr"); |
| for (q = 0, len = rows.length; q < len; q++) { |
| row = rows[q]; |
| if ((row.getAttribute("id") || "foo").match("comstat_" + t + "_")) { |
| row.style.display = "table-row"; |
| } |
| } |
| return document.getElementById("comstat_" + t + "_more").style.display = "none"; |
| }; |
| |
| comstat = function(json, state) { |
| var aa, ab, chk, dstyle, hash, i, js, key, lb, len, len1, len2, len3, m, nl, notice, oemail, p, person, q, ref, ref1, ref2, ref3, repo, row, stbl, tb, tbl, tr, u, url, wh, widget; |
| if (json && json.stats) { |
| row = new Row(); |
| p = new HTML('p', {}, globArgs.committersOnly === 'true' ? "You are currently only seeing stats for committers. To view statistics for all contributors (committers and authors), please uncheck the box below:" : "You are currently seeing stats for both committership and authorship of code. To view only committership stats, tick the box below:"); |
| chk = new HTML('input', { |
| type: 'checkbox', |
| checked: globArgs.committersOnly === 'true' ? 'checked' : null, |
| id: 'comonly', |
| onchange: 'updateWidgets("comstat", null, { committersOnly: this.checked ? "true" : null });' |
| }); |
| lb = new HTML('label', { |
| "for": 'comonly' |
| }, "Show only new committers, discard new authors."); |
| row.inject(p); |
| row.inject(chk); |
| row.inject(lb); |
| state.widget.inject(row.div, true); |
| if (json.stats.code.seen > 0) { |
| row = new Row(); |
| js = { |
| alphaSort: true, |
| counts: { |
| "Regulars": json.stats.code.seen - json.stats.code.newcomers.length, |
| "Newcomers": json.stats.code.newcomers.length |
| } |
| }; |
| widget = new Widget(4, { |
| name: "Code contributors this period", |
| representation: 'comstat' |
| }); |
| widget.json = js; |
| widget.callback = donut; |
| widget.parent = state.widget; |
| row.inject(widget); |
| donut(js, { |
| widget: widget |
| }); |
| nl = 0; |
| if (json.stats.code.newcomers.length && json.stats.code.newcomers.length >= 0) { |
| nl = json.stats.code.newcomers.length; |
| } |
| stbl = new Widget(6, { |
| name: "New code contributors (" + nl + ")" |
| }); |
| tbl = mk('table', { |
| "class": "table table-striped" |
| }); |
| tr = mk('tr', {}, [mk('th', {}, "Avatar"), mk('th', {}, "Name"), mk('th', {}, "Address"), mk('th', {}, "First commit")]); |
| app(tbl, tr); |
| tb = new HTML('tbody'); |
| json.stats.code.newcomers.sort((function(_this) { |
| return function(a, b) { |
| return json.bios[b].code[0] - json.bios[a].code[0]; |
| }; |
| })(this)); |
| dstyle = 'table-row'; |
| ref = json.stats.code.newcomers; |
| for (i = q = 0, len = ref.length; q < len; i = ++q) { |
| person = ref[i]; |
| oemail = person; |
| hash = json.bios[person].code[1].id.split('/')[1]; |
| repo = json.bios[person].code[1].sourceURL; |
| wh = new Date(json.bios[person].code[0] * 1000.0).toDateString(); |
| person = json.bios[person].bio; |
| if (i === 6) { |
| m = json.stats.code.newcomers.length - i; |
| tr = mk('tr', { |
| scope: 'row', |
| id: 'comstat_code_more' |
| }, [ |
| mk('td', { |
| colspan: "3" |
| }, new HTML('a', { |
| href: 'javascript:void(comShow("code"));' |
| }, "+" + m + " more...")) |
| ]); |
| tb.inject(tr); |
| dstyle = "none"; |
| } |
| tr = new HTML('tr', { |
| scope: 'row', |
| id: "comstat_code_" + i, |
| style: { |
| display: dstyle |
| } |
| }, [ |
| mk('td', {}, new HTML('img', { |
| style: { |
| width: '32px', |
| height: '32px' |
| }, |
| "class": "img-circle img-responsive", |
| src: "https://secure.gravatar.com/avatar/" + person.md5 + ".png?d=identicon" |
| })), mk('td', {}, mk('a', { |
| href: "?page=people&email=" + oemail |
| }, person.name)), mk('td', {}, oemail), mk('td', {}, wh + " (" + repo + ")") |
| ]); |
| tb.inject(tr); |
| } |
| app(tbl, tb); |
| stbl.inject(tbl); |
| row.inject(stbl); |
| if (json.stats.code.timeseries && json.stats.code.timeseries.length > 0) { |
| widget = new Widget(4, { |
| name: "New code contributors over time:", |
| representation: 'bars' |
| }); |
| widget.parent = state.widget; |
| row.inject(widget); |
| js = { |
| widgetType: { |
| chartType: 'bar' |
| }, |
| timeseries: json.stats.code.timeseries |
| }; |
| widget.json = js; |
| widget.callback = linechart; |
| linechart(js, { |
| widget: widget |
| }); |
| } |
| state.widget.inject(row.div); |
| } |
| if (json.stats.issues.seen > 0) { |
| row = new Row(); |
| js = { |
| alphaSort: true, |
| counts: { |
| "Regulars": json.stats.issues.seen - json.stats.issues.newcomers.length, |
| "Newcomers": json.stats.issues.newcomers.length |
| } |
| }; |
| widget = new Widget(4, { |
| name: "Issue contributors this period", |
| representation: 'comstat' |
| }); |
| widget.json = js; |
| widget.parent = state.widget; |
| widget.callback = donut; |
| row.inject(widget); |
| donut(js, { |
| widget: widget |
| }); |
| nl = 0; |
| if (json.stats.issues.newcomers.length && json.stats.issues.newcomers.length >= 0) { |
| nl = json.stats.issues.newcomers.length; |
| } |
| stbl = new Widget(6, { |
| name: "New issue contributors (" + nl + ")" |
| }); |
| tbl = mk('table', { |
| "class": "table table-striped" |
| }); |
| tr = mk('tr', {}, [mk('th', {}, "Avatar"), mk('th', {}, "Name"), mk('th', {}, "Address"), mk('th', {}, "First issue")]); |
| app(tbl, tr); |
| tb = new HTML('tbody'); |
| json.stats.issues.newcomers.sort((function(_this) { |
| return function(a, b) { |
| return json.bios[b].issue[0] - json.bios[a].issue[0]; |
| }; |
| })(this)); |
| dstyle = 'show'; |
| ref1 = json.stats.issues.newcomers; |
| for (i = u = 0, len1 = ref1.length; u < len1; i = ++u) { |
| person = ref1[i]; |
| oemail = person; |
| url = json.bios[person].issue[1].url; |
| key = json.bios[person].issue[1].key || url; |
| wh = new Date(json.bios[person].issue[0] * 1000.0).toDateString(); |
| person = json.bios[person].bio; |
| if (i === 6) { |
| m = json.stats.issues.newcomers.length - i; |
| tr = mk('tr', { |
| scope: 'row', |
| id: 'comstat_issue_more' |
| }, [ |
| mk('td', { |
| colspan: "3" |
| }, new HTML('a', { |
| href: 'javascript:void(comShow("issue"));' |
| }, "+" + m + " more...")) |
| ]); |
| tb.inject(tr); |
| dstyle = "none"; |
| } |
| tr = new HTML('tr', { |
| scope: 'row', |
| id: "comstat_issue_" + i, |
| style: { |
| display: dstyle |
| } |
| }, [ |
| mk('td', {}, new HTML('img', { |
| style: { |
| width: '32px', |
| height: '32px' |
| }, |
| "class": "img-circle img-responsive", |
| src: "https://secure.gravatar.com/avatar/" + person.md5 + ".png?d=identicon" |
| })), mk('td', {}, mk('a', { |
| href: "?page=people&email=" + oemail |
| }, person.name)), mk('td', {}, oemail), mk('td', {}, [ |
| wh + " (", mk('a', { |
| href: url || "#" |
| }, txt(key)), ")" |
| ]) |
| ]); |
| tb.inject(tr); |
| } |
| app(tbl, tb); |
| stbl.inject(tbl); |
| row.inject(stbl); |
| if (json.stats.issues.timeseries && json.stats.issues.timeseries.length > 0) { |
| widget = new Widget(6, { |
| name: "New issue contributors over time:", |
| representation: 'bars' |
| }); |
| widget.parent = state.widget; |
| row.inject(widget); |
| js = { |
| widgetType: { |
| chartType: 'bar' |
| }, |
| timeseries: json.stats.issues.timeseries |
| }; |
| widget.json = js; |
| widget.callback = linechart; |
| linechart(js, { |
| widget: widget |
| }); |
| } |
| state.widget.inject(row.div); |
| } |
| if (json.stats.converts) { |
| if (json.stats.converts.issue_to_code.length && json.stats.converts.issue_to_code.length > 0) { |
| row = new Row(); |
| stbl = new Widget(6, { |
| name: "Previous issue contributors who are now contributing code:" |
| }); |
| tbl = mk('table', { |
| "class": "table table-striped" |
| }); |
| tr = mk('tr', {}, [mk('th', {}, "Avatar"), mk('th', {}, "Name"), mk('th', {}, "Address"), mk('th', {}, "Days from first issue to first code contribution:")]); |
| app(tbl, tr); |
| tb = new HTML('tbody'); |
| ref2 = json.stats.converts.issue_to_code; |
| for (i = aa = 0, len2 = ref2.length; aa < len2; i = ++aa) { |
| person = ref2[i]; |
| if (i > 20) { |
| break; |
| } |
| tr = mk('tr', { |
| scope: 'row' |
| }, [ |
| mk('td', {}, new HTML('img', { |
| style: { |
| width: '32px', |
| height: '32px' |
| }, |
| "class": "img-circle img-responsive", |
| src: "https://secure.gravatar.com/avatar/" + person.md5 + ".png?d=identicon" |
| })), mk('td', {}, mk('a', { |
| href: "?page=people&email=" + person.address |
| }, person.name)), mk('td', {}, person.address), mk('td', { |
| style: { |
| textAlign: 'right' |
| } |
| }, (Math.floor(person.tdiff / 86400.)).pretty()) |
| ]); |
| tb.inject(tr); |
| } |
| app(tbl, tb); |
| stbl.inject(tbl); |
| row.inject(stbl); |
| state.widget.inject(row.div); |
| } |
| if (json.stats.converts.email_to_code.length && json.stats.converts.email_to_code.length > 0) { |
| row = new Row(); |
| stbl = new Widget(6, { |
| name: "Previous email authors who are now contributing code:" |
| }); |
| tbl = mk('table', { |
| "class": "table table-striped" |
| }); |
| tr = mk('tr', {}, [mk('th', {}, "Avatar"), mk('th', {}, "Name"), mk('th', {}, "Address"), mk('th', {}, "Days from first email to first code contribution:")]); |
| app(tbl, tr); |
| tb = new HTML('tbody'); |
| ref3 = json.stats.converts.email_to_code; |
| for (i = ab = 0, len3 = ref3.length; ab < len3; i = ++ab) { |
| person = ref3[i]; |
| if (i > 20) { |
| break; |
| } |
| tr = mk('tr', { |
| scope: 'row' |
| }, [ |
| mk('td', {}, new HTML('img', { |
| style: { |
| width: '32px', |
| height: '32px' |
| }, |
| "class": "img-circle img-responsive", |
| src: "https://secure.gravatar.com/avatar/" + person.md5 + ".png?d=identicon" |
| })), mk('td', {}, mk('a', { |
| href: "?page=people&email=" + person.address |
| }, person.name)), mk('td', {}, person.address), mk('td', { |
| style: { |
| textAlign: 'right' |
| } |
| }, (Math.floor(person.tdiff / 86400.)).pretty()) |
| ]); |
| tb.inject(tr); |
| } |
| app(tbl, tb); |
| stbl.inject(tbl); |
| row.inject(stbl); |
| return state.widget.inject(row.div); |
| } |
| } |
| } else { |
| notice = new HTML('h2', {}, "Community growth stats only works with user-defined views!"); |
| p = new HTML('p', {}, "To see community growth stats, please create a view of the code, email, bugs you wish to view stats for, or select an existng view in the list above"); |
| state.widget.inject(notice, true); |
| return state.widget.inject(p); |
| } |
| }; |
| |
| donut = function(json, state) { |
| var a, aa, blank, chartBox, code, comment, count, data, div, dt, dtl, el, item, l, lang, langs, len, len1, len2, q, ref, top, tot, ttot, u; |
| dt = []; |
| dtl = []; |
| l = 0; |
| tot = 0; |
| ttot = 0; |
| top = []; |
| if (json.counts) { |
| dtl = []; |
| dt = []; |
| a = 0; |
| ref = json.counts; |
| for (item in ref) { |
| count = ref[item]; |
| dt.push({ |
| name: item, |
| value: count |
| }); |
| a++; |
| } |
| if (!json.alphaSort) { |
| dt.sort((function(_this) { |
| return function(a, b) { |
| return b.value - a.value; |
| }; |
| })(this)); |
| } else { |
| dt.sort((function(_this) { |
| return function(a, b) { |
| if (a.name > b.name) { |
| return 1; |
| } else { |
| return -1; |
| } |
| }; |
| })(this)); |
| } |
| for (q = 0, len = dt.length; q < len; q++) { |
| item = dt[q]; |
| dtl.push(dt.name); |
| } |
| theme.color = genColors(a + 1, 0.55, 0.475, true); |
| } |
| if (state.widget.args.representation === 'commentcount') { |
| code = 0; |
| comment = 0; |
| blank = 0; |
| langs = json.languages; |
| for (lang in langs) { |
| data = langs[lang]; |
| code += data.code; |
| comment += data.comment; |
| blank += data.blank || 0; |
| } |
| tot = code + comment; |
| dtl = ['Code', 'Comments']; |
| dt = [ |
| { |
| name: 'Code', |
| value: code |
| }, { |
| name: 'Comments', |
| value: comment |
| } |
| ]; |
| if (blank > 0) { |
| dt.push({ |
| name: "Blanks", |
| value: blank |
| }); |
| } |
| theme.color = genColors(3, 0.6, 0.5, true); |
| } |
| if (state.widget.args.representation === 'sloccount' || (state.widget.args.representation !== 'commentcount' && json.languages)) { |
| langs = json.languages; |
| for (lang in langs) { |
| data = langs[lang]; |
| tot += data.code; |
| top.push(lang); |
| } |
| top.sort((function(_this) { |
| return function(a, b) { |
| return langs[b].code - langs[a].code; |
| }; |
| })(this)); |
| for (u = 0, len1 = top.length; u < len1; u++) { |
| lang = top[u]; |
| l++; |
| if (l > 250 || (langs[lang].code / tot) < 0.01) { |
| break; |
| } |
| ttot += langs[lang].code; |
| dt.push({ |
| name: lang, |
| value: langs[lang].code |
| }); |
| dtl.push(lang); |
| } |
| if (tot !== ttot) { |
| dtl.push('Other languages'); |
| dt.push({ |
| name: 'Other languages', |
| value: tot - ttot |
| }); |
| } |
| theme.color = genColors(17, 0.6, 0.5, true); |
| } |
| data = {}; |
| for (aa = 0, len2 = dt.length; aa < len2; aa++) { |
| el = dt[aa]; |
| data[el.name] = el.value; |
| } |
| div = new HTML('div'); |
| state.widget.inject(div, true); |
| return chartBox = new Chart(div, 'donut', data, 25); |
| }; |
| |
| factors = function(json, state) { |
| var direction, factor, h, h2, id, items, len, obj, pct, q, ref, t; |
| items = []; |
| if (json.factors) { |
| id = parseInt(Math.random() * 99999999).toString(16); |
| obj = new HTML('div', { |
| id: id |
| }); |
| ref = json.factors; |
| for (q = 0, len = ref.length; q < len; q++) { |
| factor = ref[q]; |
| h = new HTML('h1', {}, txt(factor.count.pretty())); |
| if (factor.previous) { |
| direction = factor.count - factor.previous; |
| pct = parseInt((direction / factor.previous) * 100); |
| if (direction < 0) { |
| h2 = new HTML('span', { |
| style: { |
| marginLeft: "8px", |
| fontSize: "14px", |
| color: 'red' |
| } |
| }, [ |
| new HTML('i', { |
| "class": "fa fa-chevron-circle-down" |
| }), " " + pct + "% change since last period" |
| ]); |
| h.inject(h2); |
| } else { |
| h2 = new HTML('span', { |
| style: { |
| marginLeft: "8px", |
| fontSize: "14px", |
| color: 'green' |
| } |
| }, [ |
| new HTML('i', { |
| "class": "fa fa-chevron-circle-up" |
| }), " +" + pct + "% change since last period" |
| ]); |
| h.inject(h2); |
| } |
| } |
| t = txt(factor.title); |
| obj.inject(new HTML('div', {}, [h, t])); |
| } |
| return state.widget.inject(obj, true); |
| } |
| }; |
| |
| jsondump = function(json, state) { |
| var pre; |
| pre = new HTML('pre', { |
| style: { |
| whiteSpace: 'pre-wrap' |
| } |
| }); |
| pre.inject(JSON.stringify(json, null, 2)); |
| return state.widget.inject(pre, true); |
| }; |
| |
| linechart = function(json, state) { |
| var aa, ab, cat, catdata, cats, catseries, chartBox, chk, dates, div, filled, from, histograms, id, item, key, label, len, len1, len2, len3, list, m, opt, point, q, range, ref, ref1, ref2, rv, stack, tName, to, type, u, val; |
| div = document.createElement('div'); |
| if (json.text) { |
| div.inject(new HTML('p', {}, json.text)); |
| } |
| cats = new Array(); |
| dates = new Array(); |
| catdata = {}; |
| if (!isArray(json.timeseries) && !json.counts) { |
| div.innerHTML = "No data available"; |
| state.widget.inject(div, true); |
| return; |
| } |
| if (json.timeseries) { |
| json.timeseries.sort((function(_this) { |
| return function(a, b) { |
| return a.date - b.date; |
| }; |
| })(this)); |
| ref = json.timeseries; |
| for (q = 0, len = ref.length; q < len; q++) { |
| point = ref[q]; |
| for (key in point) { |
| val = point[key]; |
| if (key !== 'date' && !(indexOf.call(cats, key) >= 0)) { |
| cats.push(key); |
| catdata[key] = new Array(); |
| } |
| } |
| } |
| ref1 = json.timeseries; |
| for (u = 0, len1 = ref1.length; u < len1; u++) { |
| point = ref1[u]; |
| m = moment(point.date * 1000); |
| rv = m.format("MMM, YYYY"); |
| if (json.histogram === "daily" || json.interval === 'day') { |
| rv = m.format("MMMM DD, YYYY"); |
| } |
| if (json.interval === 'year') { |
| rv = m.format("YYYY"); |
| } else if (json.interval === 'quarter') { |
| rv = "Q" + m.format("Q, YYYY"); |
| } else if (json.interval === 'week') { |
| rv = "Week " + m.format("W, YYYY"); |
| } |
| dates.push(rv); |
| for (key in point) { |
| val = point[key]; |
| if (key !== 'date') { |
| if (key === 'deletions') { |
| val = -val; |
| } |
| catdata[key].push(val); |
| } |
| } |
| for (aa = 0, len2 = cats.length; aa < len2; aa++) { |
| cat = cats[aa]; |
| if (ref2 = !cat, indexOf.call(point, ref2) >= 0) { |
| catdata[cat].push(0); |
| } |
| } |
| } |
| } |
| catseries = []; |
| type = 'spline'; |
| stack = false; |
| filled = true; |
| if (json.widgetType) { |
| if (json.widgetType.chartType) { |
| type = json.widgetType.chartType; |
| } |
| if (json.widgetType.stack) { |
| stack = json.widgetType.stack; |
| } |
| if (json.widgetType.nofill) { |
| filled = null; |
| } |
| } |
| if (state && state.config) { |
| if (state.config.charttype) { |
| if (state.config.charttype === 'line') { |
| type = 'line'; |
| stack = false; |
| if (!state.config.fill) { |
| filled = null; |
| } |
| } |
| if (state.config.stack) { |
| stack = true; |
| } |
| } |
| } |
| if (!state.widget.div.style.height) { |
| div.style.minHeight = "280px"; |
| } else { |
| div.style.minHeight = "100%"; |
| } |
| if (state.widget.fullscreen) { |
| div.style.minHeight = "640px"; |
| } |
| state.widget.inject(div, true); |
| range = ""; |
| if (state.widget.args.daterangeRaw) { |
| from = new Date(state.widget.args.daterangeRaw[0] * 1000).toDateString(); |
| to = new Date(state.widget.args.daterangeRaw[1] * 1000).toDateString(); |
| range = "between " + from + " and " + to; |
| } |
| chartBox = new Chart(div, 'line', json, { |
| title: range, |
| stacked: stack, |
| linetype: type, |
| filled: filled |
| }); |
| if (state.widget.args.source === 'git-evolution') { |
| id = Math.floor(Math.random() * 987654321).toString(16); |
| chk = document.createElement('input'); |
| chk.setAttribute("type", "checkbox"); |
| chk.setAttribute("id", id); |
| chk.style.marginLeft = '10px'; |
| if (globArgs.extended && globArgs.extended === 'true') { |
| chk.checked = true; |
| } |
| chk.addEventListener("change", function() { |
| var extended; |
| extended = null; |
| if (this.checked) { |
| extended = 'true'; |
| globArgs['extended'] = 'true'; |
| } |
| return updateWidgets('line', null, { |
| extended: extended |
| }); |
| }); |
| state.widget.inject(mk('br')); |
| state.widget.inject(chk); |
| label = document.createElement('label'); |
| label.setAttribute("for", id); |
| label.setAttribute("title", "Check this box to view evolutionary breakdown of languages"); |
| chk.setAttribute("title", "Check this box to view evolutionary breakdown of languages"); |
| label.style.paddingLeft = '5px'; |
| label.appendChild(document.createTextNode('Toggle language breakdown')); |
| state.widget.inject(label); |
| if (globArgs.extended) { |
| id = Math.floor(Math.random() * 987654321).toString(16); |
| chk = document.createElement('input'); |
| chk.setAttribute("type", "checkbox"); |
| chk.setAttribute("id", id); |
| chk.style.marginLeft = '10px'; |
| if (globArgs.codeonly && globArgs.codeonly === 'true') { |
| chk.checked = true; |
| } |
| chk.addEventListener("change", function() { |
| var codeonly; |
| codeonly = null; |
| if (this.checked) { |
| codeonly = 'true'; |
| globArgs['codeonly'] = 'true'; |
| } |
| return updateWidgets('line', null, { |
| codeonly: codeonly |
| }); |
| }); |
| state.widget.inject(chk); |
| label = document.createElement('label'); |
| label.setAttribute("for", id); |
| label.setAttribute("title", "Check this box to show only programming languages (no docs/markups/build-configs)"); |
| chk.setAttribute("title", "Check this box to show only programming languages (no docs/markups/build-configs)"); |
| label.style.paddingLeft = '5px'; |
| label.appendChild(document.createTextNode('Only show programming languages')); |
| state.widget.inject(label); |
| } |
| } |
| if ((!state["public"]) && json.interval) { |
| tName = 'interval'; |
| list = document.createElement('select'); |
| list.setAttribute("data", tName); |
| state.widget.inject(mk('br')); |
| state.widget.inject(txt("Select interval: ")); |
| state.widget.inject(list); |
| histograms = ['day', 'week', 'month', 'quarter', 'year']; |
| if (state.widget.wargs && state.widget.wargs.histogram === 'hour') { |
| histograms.unshift('hour'); |
| } |
| for (ab = 0, len3 = histograms.length; ab < len3; ab++) { |
| item = histograms[ab]; |
| opt = document.createElement('option'); |
| opt.value = item; |
| opt.text = item; |
| if ((globArgs[tName] && globArgs[tName] === item) || json.interval === item) { |
| opt.selected = 'selected'; |
| } |
| list.appendChild(opt); |
| } |
| return list.addEventListener("change", function() { |
| var source, x; |
| source = this.value; |
| if (source === "") { |
| source = null; |
| } |
| tName = this.getAttribute("data"); |
| globArgs[tName] = source; |
| x = {}; |
| x[tName] = source; |
| return updateWidgets('line', null, x); |
| }, false); |
| } |
| }; |
| |
| worldmap = function(json, state) { |
| var cmax, ctotal, details, dt, dtl, echartMap, item, l, lmain, radius, ref, top, tot, ttot; |
| dt = []; |
| dtl = []; |
| l = 0; |
| tot = 0; |
| ttot = 0; |
| top = []; |
| cmax = 0; |
| ctotal = 0; |
| if (json.countries) { |
| ref = json.countries; |
| for (item in ref) { |
| details = ref[item]; |
| dt.push({ |
| name: details.name, |
| value: details.count |
| }); |
| ctotal += details.count; |
| if (details.count > cmax) { |
| cmax = details.count; |
| } |
| } |
| } |
| lmain = document.createElement('div'); |
| radius = ['30%', '50%']; |
| if (!state.widget.div.style.height) { |
| lmain.style.height = "500px"; |
| } else { |
| lmain.style.height = "100%"; |
| } |
| if (state.widget.fullscreen) { |
| lmain.style.height = "1000px"; |
| radius = ['35%', '60%']; |
| theme.textStyle.fontSize = 20; |
| } |
| lmain.style.width = "100%"; |
| state.widget.inject(lmain, true); |
| echartMap = echarts.init(lmain, theme); |
| echartMap.setOption({ |
| title: { |
| text: "Worldwide distribution by country", |
| subtext: "(" + ctotal.pretty() + " in total from " + (json.numberOfCountries || 0) + " countries)" |
| }, |
| calculable: true, |
| dataRange: { |
| min: 0, |
| max: cmax, |
| text: ['High', 'Low'], |
| realtime: false, |
| calculable: true, |
| color: ['orangered', 'yellow', 'lightskyblue'] |
| }, |
| toolbox: { |
| show: true, |
| feature: { |
| dataView: { |
| show: true, |
| title: 'Data view', |
| readOnly: false, |
| lang: ['Data View', 'Close', 'Update'] |
| }, |
| restore: { |
| show: true, |
| title: "Restore" |
| }, |
| saveAsImage: { |
| show: true, |
| title: "Save Image" |
| } |
| } |
| }, |
| tooltip: { |
| trigger: 'item', |
| formatter: function(params) { |
| return params.seriesName + '<br/>' + params.name + ' : ' + (params.value || 0).pretty(); |
| } |
| }, |
| series: [ |
| { |
| name: state.widget.name, |
| type: 'map', |
| mapType: 'world', |
| mapLocation: { |
| y: 60 |
| }, |
| itemStyle: { |
| emphasis: { |
| label: { |
| show: true |
| } |
| } |
| }, |
| data: dt |
| } |
| ] |
| }); |
| return theme.textStyle.fontSize = 12; |
| }; |
| |
| messages = function(json, state) { |
| var a, aa, ab, b, btn, div, el, form, h2, inp, item, items, len, len1, len2, len3, message, obj, pre, q, ref, ref1, ref2, reply, tbl, tbody, td, thead, tr, u; |
| if (isArray(json)) { |
| obj = document.createElement('form'); |
| tbl = mk('table'); |
| set(tbl, 'class', 'table table-striped'); |
| thead = mk('thead'); |
| tr = mk('tr'); |
| ref = ['Date', 'Sender', 'Subject']; |
| for (q = 0, len = ref.length; q < len; q++) { |
| el = ref[q]; |
| td = mk('th'); |
| if (el.match(/(Date|Sender)/)) { |
| td.style.width = "20%"; |
| } |
| app(td, txt(el)); |
| app(tr, td); |
| } |
| app(thead, tr); |
| app(tbl, thead); |
| tbody = mk('tbody'); |
| app(tbl, tbody); |
| for (u = 0, len1 = json.length; u < len1; u++) { |
| message = json[u]; |
| tr = mk('tr'); |
| if (message.read === false) { |
| tr.style.fontWeight = "bold"; |
| tr.style.color = "#396"; |
| } |
| td = mk('td'); |
| a = mk('a'); |
| set(a, 'href', '?page=messages&message=' + message.id); |
| app(a, txt(new Date(message.epoch * 1000).toString())); |
| app(td, a); |
| app(tr, td); |
| td = mk('td'); |
| a = mk('a'); |
| set(a, 'href', '?page=messages&message=' + message.id); |
| app(a, txt(message.senderName)); |
| app(td, a); |
| app(tr, td); |
| td = mk('td'); |
| a = mk('a'); |
| set(a, 'href', '?page=messages&message=' + message.id); |
| app(a, txt(message.subject)); |
| app(td, a); |
| app(tr, td); |
| app(tbody, tr); |
| } |
| app(obj, tbl); |
| items = { |
| recipient: 'Recipient ID', |
| subject: "Message subject", |
| body: "Message" |
| }; |
| h2 = mk('h2'); |
| app(h2, txt("Send a message:")); |
| app(obj, h2); |
| ref1 = ['recipient', 'subject', 'body']; |
| for (aa = 0, len2 = ref1.length; aa < len2; aa++) { |
| item = ref1[aa]; |
| div = mk('div'); |
| app(div, txt(items[item] + ": ")); |
| if (item === 'body') { |
| inp = mk('textarea'); |
| inp.style.width = "600px"; |
| inp.style.height = "200px"; |
| } else { |
| inp = mk('input'); |
| set(inp, 'type', 'text'); |
| inp.style.width = "200px"; |
| } |
| set(inp, 'name', item); |
| app(div, inp); |
| app(obj, div); |
| } |
| btn = mk('input'); |
| set(btn, 'type', 'button'); |
| set(btn, 'onclick', 'sendEmail(this.form)'); |
| set(btn, 'value', "Send message"); |
| app(obj, btn); |
| return state.widget.inject(obj, true); |
| } else { |
| obj = mk('div'); |
| b = mk('b'); |
| app(b, txt("Sender: ")); |
| app(obj, b); |
| app(obj, txt(json.senderName + ' (' + json.sender + ')')); |
| app(obj, mk('br')); |
| b = mk('b'); |
| app(b, txt("Date: ")); |
| app(obj, b); |
| app(obj, txt(new Date(json.epoch * 1000).toString())); |
| app(obj, mk('br')); |
| b = mk('b'); |
| app(b, txt("Subject: ")); |
| app(obj, b); |
| app(obj, txt(json.subject)); |
| app(obj, mk('br')); |
| app(obj, mk('br')); |
| pre = mk('pre'); |
| app(pre, txt(json.body)); |
| app(obj, pre); |
| app(obj, mk('hr')); |
| form = mk('form'); |
| items = { |
| recipient: 'Recipient ID', |
| subject: "Message subject", |
| body: "Message" |
| }; |
| h2 = mk('h2'); |
| app(h2, txt("Send a reply:")); |
| app(form, h2); |
| reply = { |
| recipient: json.sender, |
| subject: 'RE: ' + json.subject, |
| body: '' |
| }; |
| ref2 = ['recipient', 'subject', 'body']; |
| for (ab = 0, len3 = ref2.length; ab < len3; ab++) { |
| item = ref2[ab]; |
| div = mk('div'); |
| app(div, txt(items[item] + ": ")); |
| if (item === 'body') { |
| inp = mk('textarea'); |
| inp.style.width = "600px"; |
| inp.style.height = "200px"; |
| } else { |
| inp = mk('input'); |
| set(inp, 'type', 'text'); |
| inp.style.width = "200px"; |
| } |
| inp.value = reply[item]; |
| set(inp, 'name', item); |
| app(div, inp); |
| app(form, div); |
| } |
| btn = mk('input'); |
| set(btn, 'type', 'button'); |
| set(btn, 'onclick', 'sendEmail(this.form)'); |
| set(btn, 'value', "Send message"); |
| app(form, btn); |
| app(obj, form); |
| return state.widget.inject(obj, true); |
| } |
| }; |
| |
| sendEmail = function(form) { |
| var i, js, k, q, ref, v; |
| js = { |
| action: 'send' |
| }; |
| for (i = q = 0, ref = form.length - 1; 0 <= ref ? q <= ref : q >= ref; i = 0 <= ref ? ++q : --q) { |
| k = form[i].name; |
| v = form[i].value; |
| if (k === 'recipient' || k === 'subject' || k === 'body') { |
| js[k] = v; |
| } |
| } |
| return postJSON("messages", js, null, function(a) { |
| return alert("Mail sent!"); |
| }); |
| }; |
| |
| mvp = function(json, state) { |
| var aa, el, i, len, len1, len2, nlist, person, q, ref, ref1, ref2, tb, tbl, tr, u; |
| nlist = new HTML('select', { |
| name: 'size', |
| id: 'size' |
| }); |
| ref = [10, 20, 50, 100, 200, 500, 1000, 2000]; |
| for (q = 0, len = ref.length; q < len; q++) { |
| i = ref[q]; |
| el = new HTML('option', { |
| value: i, |
| text: i + "" |
| }); |
| if (globArgs.size && parseInt(globArgs.size) === i) { |
| el.selected = 'selected'; |
| } |
| el.inject(txt(i + "")); |
| nlist.inject(el); |
| } |
| nlist.addEventListener("change", function() { |
| var n; |
| n = this.value; |
| if (n === "") { |
| n = null; |
| } |
| globArgs.size = n; |
| return updateWidgets('mvp', null, { |
| size: n |
| }); |
| }, false); |
| state.widget.inject(new HTML('b', {}, "List size: "), true); |
| state.widget.inject(nlist); |
| nlist = new HTML('select', { |
| name: 'sort', |
| id: 'sort' |
| }); |
| ref1 = ['commits', 'issues', 'emails']; |
| for (u = 0, len1 = ref1.length; u < len1; u++) { |
| i = ref1[u]; |
| el = new HTML('option', { |
| value: i, |
| text: i |
| }); |
| if (globArgs.sort && globArgs.sort === i) { |
| el.selected = 'selected'; |
| } |
| el.inject(txt(i)); |
| nlist.inject(el); |
| } |
| nlist.addEventListener("change", function() { |
| var n; |
| n = this.value; |
| if (n === "") { |
| n = null; |
| } |
| globArgs.sort = n; |
| return updateWidgets('mvp', null, { |
| sort: n |
| }); |
| }, false); |
| state.widget.inject(new HTML('b', {}, " Sort by: ")); |
| state.widget.inject(nlist); |
| tbl = mk('table', { |
| "class": "table table-striped" |
| }); |
| tr = mk('tr', {}, [mk('th', {}, "Rank"), mk('th', {}, "Avatar"), mk('th', {}, "Name"), mk('th', {}, "Address"), mk('th', {}, globArgs.author ? "Authorings" : "Commits"), mk('th', {}, "Issues"), mk('th', {}, "Email")]); |
| app(tbl, tr); |
| tb = new HTML('tbody'); |
| ref2 = json.sorted; |
| for (i = aa = 0, len2 = ref2.length; aa < len2; i = ++aa) { |
| person = ref2[i]; |
| tr = mk('tr', { |
| scope: 'row' |
| }, [ |
| mk('td', {}, (i + 1).pretty()), mk('td', {}, new HTML('img', { |
| style: { |
| width: '32px', |
| height: '32px' |
| }, |
| "class": "img-circle img-responsive", |
| src: "https://secure.gravatar.com/avatar/" + person.md5 + ".png?d=identicon" |
| })), mk('td', {}, mk('a', { |
| href: "?page=people&email=" + person.address |
| }, person.name)), mk('td', {}, person.address), mk('td', {}, person.commits.pretty()), mk('td', {}, person.issues.pretty()), mk('td', {}, person.emails.pretty()) |
| ]); |
| tb.inject(tr); |
| } |
| app(tbl, tb); |
| return state.widget.inject(tbl); |
| }; |
| |
| paragraph = function(json, state) { |
| var len, lmain, p, para, q, ref, results, title; |
| lmain = mk('div'); |
| state.widget.parent.inject(lmain, true); |
| if (json.title) { |
| title = mk('h1', {}, json.title); |
| app(lmain, title); |
| } |
| if (json.text) { |
| if (isArray(json.text)) { |
| ref = json.text; |
| results = []; |
| for (q = 0, len = ref.length; q < len; q++) { |
| p = ref[q]; |
| para = mk('p', { |
| style: "font-size: 1.2rem;" |
| }, p); |
| results.push(app(lmain, para)); |
| } |
| return results; |
| } else { |
| return app(lmain, mk('p', { |
| style: "font-size: 1.2rem;" |
| }, json.text)); |
| } |
| } |
| }; |
| |
| preferences = function(json, state) { |
| var a, aobj, btn, desc, div, h1, h3, i, id, inp, item, items, len, len1, list, name, obj, opt, org, q, ref, ref1, ref2, u; |
| obj = document.createElement('form'); |
| items = { |
| screenname: 'Screen name', |
| fullname: "Full name", |
| email: "Email address", |
| tag: "Organisation filter tag", |
| token: "API token" |
| }; |
| desc = { |
| tag: "If set, only sources with this tag will be shown in your views." |
| }; |
| ref = ['screenname', 'fullname', 'email', 'tag', 'token']; |
| for (q = 0, len = ref.length; q < len; q++) { |
| item = ref[q]; |
| div = mk('div'); |
| app(div, txt(items[item] + ": ")); |
| inp = mk('input'); |
| set(inp, 'type', 'text'); |
| set(inp, 'name', item); |
| inp.style.width = "200px"; |
| if (item === 'token') { |
| set(inp, "readonly", "readonly"); |
| set(inp, "disabled", "disabled"); |
| inp.style.width = "700px"; |
| } |
| set(inp, 'value', json[item] ? json[item] : ''); |
| app(div, inp); |
| if (desc[item]) { |
| i = mk('i'); |
| i.style.fontSize = "9pt"; |
| i.style.marginLeft = "20px"; |
| app(i, txt(desc[item])); |
| app(div, i); |
| } |
| app(obj, div); |
| } |
| div = mk('div'); |
| app(div, txt("Organisation to view: ")); |
| list = mk('select'); |
| set(list, 'name', 'organisation'); |
| ref1 = json.orgs; |
| for (u = 0, len1 = ref1.length; u < len1; u++) { |
| org = ref1[u]; |
| opt = mk('option'); |
| opt.value = org; |
| opt.text = org; |
| if (org === json.organisation) { |
| opt.selected = 'selected'; |
| } |
| app(list, opt); |
| } |
| app(div, list); |
| app(obj, div); |
| btn = mk('input'); |
| set(btn, 'type', 'button'); |
| set(btn, 'onclick', 'saveprefs(this.form)'); |
| set(btn, 'value', "Save preferences"); |
| app(obj, btn); |
| state.widget.inject(obj, true); |
| if (json.admin) { |
| aobj = mk('div'); |
| app(aobj, mk('br')); |
| app(aobj, mk('br')); |
| h1 = mk('h2'); |
| app(h1, txt("Organisation administration:")); |
| app(aobj, h1); |
| app(aobj, txt("If you are an organisation administrator, you may edit your organisation(s) by selecting the org you wish to edit below:")); |
| ref2 = json.admin; |
| for (id in ref2) { |
| name = ref2[id]; |
| a = mk('a'); |
| set(a, 'href', '?page=orgadmin&org=' + id); |
| h3 = mk('h4'); |
| app(h3, txt("- " + name)); |
| app(a, h3); |
| app(aobj, a); |
| } |
| return state.widget.inject(aobj); |
| } |
| }; |
| |
| saveprefs = function(form) { |
| var i, js, k, q, ref, v; |
| js = { |
| action: 'save' |
| }; |
| for (i = q = 0, ref = form.length - 1; 0 <= ref ? q <= ref : q >= ref; i = 0 <= ref ? ++q : --q) { |
| k = form[i].name; |
| v = form[i].value; |
| if (k === 'screenname' || k === 'fullname' || k === 'email' || k === 'tag' || k === 'organisation') { |
| js[k] = v; |
| } |
| } |
| return postJSON("preferences", js, null, function(a) { |
| return alert("Preferences saved!"); |
| }); |
| }; |
| |
| viewJS = {}; |
| |
| publisherWidget = null; |
| |
| publisherPublic = function(json, state) { |
| return publisher(json, state, true); |
| }; |
| |
| publisher = function(json, state, nolink) { |
| var div, link, twidget; |
| div = document.createElement('div'); |
| state["public"] = true; |
| twidget = json.widget.replace(/(-\d?year|-all|-month)/, ""); |
| if (twidget === 'repo-relationship' || twidget === 'issue-relationship' || twidget === 'mail-relationship') { |
| relationship(json, state); |
| } |
| if (twidget === 'languages' || twidget === 'compare-commits' || twidget === 'repo-size' || twidget === 'repo-commits') { |
| donut(json, state); |
| } else if (twidget === 'evolution' || twidget === 'evolution-extended' || twidget === 'commit-history' || twidget === 'committer-count' || twidget === 'issue-count' || twidget === 'issue-operators' || twidget === 'commit-lines' || twidget === 'email-count' || twidget === 'issue-queue' || twidget === 'file-age' || twidget === 'file-creation' || twidget === 'im-stats' || twidget === 'log-stats') { |
| linechart(json, state); |
| } else if (twidget === 'log-map') { |
| worldmap(json, state); |
| } else if (twidget === 'sloc-map') { |
| treemap(json, state); |
| } else if (twidget.match(/top/)) { |
| top5(json, state); |
| } |
| viewJS = JSON.stringify({ |
| view: json.eview, |
| widget: json.widget |
| }); |
| if (!nolink) { |
| link = mk('input', { |
| type: "button", |
| "class": "btn btn-success", |
| value: "Publish this widget", |
| onclick: "publishWidget();" |
| }); |
| state.widget.inject(link); |
| return publisherWidget = state.widget; |
| } else { |
| if (!location.href.match(/snoot\.io/)) { |
| link = mk('a', { |
| href: "https://www.snoot.io/", |
| style: "font-size: 10px; margin-left: 60px; font-family: sans-serif;" |
| }, "Data courtesy of Snoot.io"); |
| return state.widget.inject(link); |
| } |
| } |
| }; |
| |
| publishWidget = function() { |
| return postJSON("publish", { |
| publish: JSON.parse(viewJS) |
| }, null, postPublishLink); |
| }; |
| |
| postPublishLink = function(json, state) { |
| var added, pdiv; |
| if (json.id) { |
| pdiv = get('publishercode'); |
| if (!pdiv) { |
| pdiv = mk('pre', { |
| id: "publishercode", |
| style: "padding: 5px; border: 1px dashed #333; background: #FFD;" |
| }); |
| publisherWidget.inject(pdiv); |
| } |
| pdiv.innerHTML = ""; |
| added = ""; |
| if (json.type && json.type.match(/log-map/)) { |
| added = "\n<script src=\"https://www.snoot.io/js/worldmap.js\"></script>\n"; |
| } |
| return app(pdiv, txt("Script code for publishing:\n\n<div class=\"snoot-widget\" data=\"" + json.id + ("\"></div>\n<script src=\"https://www.snoot.io/js/snoot.all.3.js\"></script>\n<script src=\"https://www.snoot.io/publish/bundle.js\"></script>" + added))); |
| } else { |
| return alert("Something broke :("); |
| } |
| }; |
| |
| radarIndicators = []; |
| |
| radar = function(json, state) { |
| var chk, id, label, lmain, radarChart; |
| lmain = new HTML('div'); |
| state.widget.inject(lmain, true); |
| radarChart = new Chart(lmain, 'radar', json.radar); |
| id = Math.floor(Math.random() * 987654321).toString(16); |
| chk = document.createElement('input'); |
| chk.setAttribute("type", "checkbox"); |
| chk.setAttribute("id", id); |
| chk.style.marginLeft = '10px'; |
| if (globArgs.harmonize && globArgs.harmonize === 'true') { |
| chk.checked = true; |
| } |
| chk.addEventListener("change", function() { |
| var harmonize; |
| harmonize = null; |
| if (this.checked) { |
| harmonize = 'true'; |
| globArgs['harmonize'] = 'true'; |
| } |
| return updateWidgets('radar', null, { |
| harmonize: harmonize |
| }); |
| }); |
| state.widget.inject(mk('br')); |
| state.widget.inject(chk); |
| label = document.createElement('label'); |
| label.setAttribute("for", id); |
| label.setAttribute("title", "Check this box to harmonize edges to organisational averages"); |
| chk.setAttribute("title", "Check this box to harmonize edges to organisational averages"); |
| label.style.paddingLeft = '5px'; |
| label.appendChild(document.createTextNode('Harmonize edges')); |
| state.widget.inject(label); |
| id = Math.floor(Math.random() * 987654321).toString(16); |
| chk = document.createElement('input'); |
| chk.setAttribute("type", "checkbox"); |
| chk.setAttribute("id", id); |
| chk.style.marginLeft = '10px'; |
| if (globArgs.relativize && globArgs.relativize === 'true') { |
| chk.checked = true; |
| } |
| chk.addEventListener("change", function() { |
| var relativize; |
| relativize = null; |
| if (this.checked) { |
| relativize = 'true'; |
| globArgs['relativize'] = 'true'; |
| } |
| return updateWidgets('radar', null, { |
| relativize: relativize |
| }); |
| }); |
| state.widget.inject(mk('br')); |
| state.widget.inject(chk); |
| label = document.createElement('label'); |
| label.setAttribute("for", id); |
| label.setAttribute("title", "Check this box to force all areas to be relative to their own projects (and not the compared projects). This may help to display foucs areas."); |
| chk.setAttribute("title", "Check this box to force all areas to be relative to their own projects (and not the compared projects). This may help to display foucs areas."); |
| label.style.paddingLeft = '5px'; |
| label.appendChild(document.createTextNode('Make all projects relative to themselves')); |
| return state.widget.inject(label); |
| }; |
| |
| relationship = function(json, state) { |
| var chart, div, i, id, invchk, invlbl, opt, q, sigsel; |
| div = document.createElement('div'); |
| state.widget.inject(div, true); |
| chart = new Chart(div, 'relationship', json, {}); |
| id = Math.floor(Math.random() * 987654321).toString(16); |
| invchk = new HTML('input', { |
| "class": "uniform", |
| style: { |
| marginRight: "10px" |
| }, |
| id: "author_" + id, |
| type: 'checkbox', |
| checked: globArgs.author, |
| name: 'author', |
| value: 'true' |
| }); |
| invchk.addEventListener("change", function() { |
| var author; |
| author = null; |
| if (this.checked) { |
| author = 'true'; |
| globArgs['author'] = 'true'; |
| } |
| return updateWidgets('relationship', null, { |
| author: author |
| }); |
| }); |
| invlbl = new HTML('label', { |
| "for": "author_" + id |
| }, "Inverse map (sender <-> recipient)"); |
| state.widget.inject(invchk); |
| state.widget.inject(invlbl); |
| state.widget.inject(new HTML('br')); |
| state.widget.inject(new HTML('span', {}, "Minimum signal strength: ")); |
| sigsel = new HTML('select', { |
| id: "signal_" + id |
| }); |
| for (i = q = 1; q <= 5; i = ++q) { |
| opt = new HTML('option', { |
| value: i, |
| selected: String(i) === globArgs.links ? "selected" : null |
| }, String(i)); |
| sigsel.inject(opt); |
| } |
| sigsel.addEventListener("change", function() { |
| var links; |
| links = null; |
| if (this.value) { |
| links = this.value; |
| globArgs['links'] = links; |
| } |
| return updateWidgets('relationship', null, { |
| links: links |
| }); |
| }); |
| return state.widget.inject(sigsel); |
| }; |
| |
| rcollate = function(list) { |
| var line, out; |
| out = ""; |
| while (list.length > 2) { |
| line = list.shift(); |
| out += line + ", "; |
| } |
| if (list.length > 1) { |
| out += list[0] + " and " + list[1]; |
| } else { |
| return list[0]; |
| } |
| return out; |
| }; |
| |
| report = function(json, state) { |
| var active, age, ageInMonths, ageInYears, carr, div, p, pct, rtext, stitle, title; |
| div = document.createElement('div'); |
| state.widget.inject(div, true); |
| if (json.projectAge === 0) { |
| app(div, mk('h3', {}, "We were unable to determine the age of this project, sorry!")); |
| return; |
| } |
| ageInMonths = parseInt(json.projectAge / (86400 * 30.3)); |
| ageInYears = parseInt(json.projectAge / (86400 * 365.25)); |
| age = mk('h3', {}, "Estimated age of project: " + ageInMonths + " months (" + ageInYears + " years)"); |
| app(div, age); |
| if (ageInYears >= 1) { |
| title = mk('h2', {}, "Long range trends:"); |
| app(div, title); |
| stitle = mk('h3', {}, "Commits:"); |
| carr = []; |
| if (ageInYears >= 5) { |
| pct = json.commits['5'].angle; |
| rtext = "a rapid decline in commits in the long term (5+ years)"; |
| if (pct > -50) { |
| rtext = "a moderate decline in commits in the long term (5+ years)"; |
| } |
| if (pct > -30) { |
| rtext = "a slow decline in commits in the long term (5+ years)"; |
| } |
| if (pct > -10) { |
| rtext = "a steady rate of commits in the long term (5+ years)"; |
| } |
| if (pct > 10) { |
| rtext = "a slow increase in commits in the long term (5+ years)"; |
| } |
| if (pct > 30) { |
| rtext = "a moderate increase in commits in the long term (5+ years)"; |
| } |
| if (pct > 50) { |
| rtext = "a strong increase in commits in the long term (5+ years)"; |
| } |
| carr.push(rtext); |
| } |
| if (ageInYears >= 2) { |
| pct = json.commits['2'].angle; |
| rtext = "a rapid decline in commits in the medium term (2 years)"; |
| if (pct > -50) { |
| rtext = "a moderate decline in commits in the medium term (2 years)"; |
| } |
| if (pct > -30) { |
| rtext = "a slow decline in commits in the medium term (2 years)"; |
| } |
| if (pct > -10) { |
| rtext = "a steady rate of commits in the medium term (2 years)"; |
| } |
| if (pct > 10) { |
| rtext = "a slow increase in commits in the medium term (2 years)"; |
| } |
| if (pct > 30) { |
| rtext = "a moderate increase in commits in the medium term (2 years)"; |
| } |
| if (pct > 50) { |
| rtext = "a strong increase in commits in the medium term (2 years)"; |
| } |
| carr.push(rtext); |
| } |
| if (ageInYears >= 1) { |
| pct = json.commits['1'].angle; |
| rtext = "a rapid decline in commits in the short term (past year)"; |
| if (pct > -50) { |
| rtext = "a moderate decline in commits in the short term (past year)"; |
| } |
| if (pct > -30) { |
| rtext = "a slow decline in commits in the short term (past year)"; |
| } |
| if (pct > -10) { |
| rtext = "a steady rate of commits in the short term (past year)"; |
| } |
| if (pct > 10) { |
| rtext = "a slow increase in commits in the short term (past year)"; |
| } |
| if (pct > 30) { |
| rtext = "a moderate increase in commits in the short term (past year)"; |
| } |
| if (pct > 50) { |
| rtext = "a strong increase in commits in the short term (past year)"; |
| } |
| carr.push(rtext); |
| } |
| p = mk('p', {}, "This project has experienced " + rcollate(carr) + "."); |
| app(div, stitle); |
| app(div, p); |
| stitle = mk('h3', {}, "Contributors:"); |
| carr = []; |
| if (ageInYears >= 5) { |
| pct = json.authors['5'].authors.angle; |
| rtext = "a rapid decline in contributors in the long term (5+ years)"; |
| if (pct > -50) { |
| rtext = "a moderate decline in contributors in the long term (5+ years)"; |
| } |
| if (pct > -30) { |
| rtext = "a slow decline in contributors in the long term (5+ years)"; |
| } |
| if (pct > -10) { |
| rtext = "a steady rate of contributors in the long term (5+ years)"; |
| } |
| if (pct > 10) { |
| rtext = "a slow increase in contributors in the long term (5+ years)"; |
| } |
| if (pct > 30) { |
| rtext = "a moderate increase in contributors in the long term (5+ years)"; |
| } |
| if (pct > 50) { |
| rtext = "a strong increase in contributors in the long term (5+ years)"; |
| } |
| carr.push(rtext); |
| } |
| if (ageInYears >= 2) { |
| pct = json.authors['2'].authors.angle; |
| rtext = "a rapid decline in contributors in the medium term (2 years)"; |
| if (pct > -50) { |
| rtext = "a moderate decline in contributors in the medium term (2 years)"; |
| } |
| if (pct > -30) { |
| rtext = "a slow decline in contributors in the medium term (2 years)"; |
| } |
| if (pct > -10) { |
| rtext = "a steady rate of contributors in the medium term (2 years)"; |
| } |
| if (pct > 10) { |
| rtext = "a slow increase in contributors in the medium term (2 years)"; |
| } |
| if (pct > 30) { |
| rtext = "a moderate increase in contributors in the medium term (2 years)"; |
| } |
| if (pct > 50) { |
| rtext = "a strong increase in contributors in the medium term (2 years)"; |
| } |
| carr.push(rtext); |
| } |
| if (ageInYears >= 1) { |
| pct = json.authors['1'].authors.angle; |
| rtext = "a rapid decline in contributors in the short term (past year)"; |
| if (pct > -50) { |
| rtext = "a moderate decline in contributors in the short term (past year)"; |
| } |
| if (pct > -30) { |
| rtext = "a slow decline in contributors in the short term (past year)"; |
| } |
| if (pct > -10) { |
| rtext = "a steady rate of contributors in the short term (past year)"; |
| } |
| if (pct > 10) { |
| rtext = "a slow increase in contributors in the short term (past year)"; |
| } |
| if (pct > 30) { |
| rtext = "a moderate increase in contributors in the short term (past year)"; |
| } |
| if (pct > 50) { |
| rtext = "a strong increase in contributors in the short term (past year)"; |
| } |
| carr.push(rtext); |
| active = parseInt(json.authors['1'].authors.average); |
| carr.push("currently has " + active + " active contributors"); |
| } |
| p = mk('p', {}, "The project has had " + rcollate(carr) + "."); |
| app(div, stitle); |
| return app(div, p); |
| } |
| }; |
| |
| make5 = function(obj, json, pos) { |
| var filter, fodder, i, idiv, item, k, left, len, q, ref, ref1, results, right, rightInner, t, title, v, what; |
| what = json.topN.denoter; |
| ref = json.topN.items.slice(pos, pos + 5); |
| results = []; |
| for (i = q = 0, len = ref.length; q < len; i = ++q) { |
| item = ref[i]; |
| if (i === 5) { |
| break; |
| } |
| idiv = new HTML('div', { |
| "class": "media event" |
| }); |
| left = new HTML('a', { |
| "class": "pull-left" |
| }); |
| if (item.gravatar) { |
| left.inject(new HTML('img', { |
| "class": "img-circle img-reponsive", |
| src: "https://secure.gravatar.com/avatar/" + item.gravatar + ".png?d=identicon", |
| style: { |
| width: "32px", |
| height: "32px" |
| } |
| })); |
| } else if (json.topN.icon) { |
| left.inject(new HTML('i', { |
| "class": "fa fa-" + json.topN.icon, |
| style: { |
| fontSize: "28px" |
| } |
| })); |
| } |
| right = new HTML('div', { |
| "class": "media event" |
| }); |
| rightInner = new HTML('div', { |
| "class": "media-body" |
| }); |
| right.inject(rightInner); |
| if (item.email) { |
| title = new HTML('a', { |
| "class": "title", |
| href: "contributors.html?page=biography&email=" + item.email |
| }, txt(item.name)); |
| rightInner.inject(title); |
| rightInner.inject(" - "); |
| filter = new HTML('a', { |
| "class": "title", |
| href: "javascript: void(filterPerson('" + item.email + "'));" |
| }, "[filter]"); |
| rightInner.inject(filter); |
| } else if (item.url) { |
| if (item.title) { |
| item.tooltip = item.title; |
| if (item.title.length > 40) { |
| item.title = item.title.toString().substring(0, 40) + "..."; |
| } |
| item.name += ": " + item.title; |
| } |
| item.url = item.url.replace(/([^:])(\/\/+)/g, '$1/'); |
| title = new HTML('a', { |
| title: item.tooltip, |
| "class": "title", |
| href: item.url |
| }, txt(item.name)); |
| rightInner.inject(title); |
| } else { |
| title = new HTML('a', { |
| "class": "title" |
| }, txt(item.name)); |
| rightInner.inject(title); |
| } |
| fodder = new HTML('p', {}); |
| fodder.inject(new HTML('b', {}, item.count.pretty())); |
| fodder.inject(txt(" " + what + " during this period")); |
| if (item.subcount) { |
| fodder.inject(new HTML('br')); |
| t = []; |
| ref1 = item.subcount; |
| for (k in ref1) { |
| v = ref1[k]; |
| t.push(v.pretty() + " " + k); |
| } |
| fodder.inject(new HTML('small', {}, t.join(", ") + ".")); |
| } |
| rightInner.inject(fodder); |
| idiv.inject(left); |
| idiv.inject(right); |
| results.push(obj.inject(idiv)); |
| } |
| return results; |
| }; |
| |
| top5 = function(json, state) { |
| var id, items, nid, obj, pos, results; |
| items = []; |
| if (json.topN) { |
| id = parseInt(Math.random() * 99999999).toString(16); |
| obj = new HTML('div', { |
| id: id |
| }); |
| make5(obj, json, 0); |
| state.widget.inject(obj, true); |
| pos = 5; |
| results = []; |
| while (pos < json.topN.items.length) { |
| nid = id + "_show_" + pos; |
| obj.inject(new HTML('a', { |
| style: { |
| cursor: 'pointer' |
| }, |
| onclick: "this.style.display = 'none'; get('" + nid + "').style.display = 'block';" |
| }, "Show more...")); |
| obj = new HTML('div', { |
| id: nid, |
| style: { |
| display: 'none' |
| } |
| }); |
| make5(obj, json, pos); |
| state.widget.inject(obj); |
| results.push(pos += 5); |
| } |
| return results; |
| } |
| }; |
| |
| showMore = function(id) { |
| var obj; |
| obj = document.getElementById(id); |
| if (obj) { |
| return obj.style.display = "block"; |
| } |
| }; |
| |
| filterPerson = function(email) { |
| if (email === "") { |
| email = null; |
| } |
| updateWidgets('donut', null, { |
| email: email |
| }); |
| updateWidgets('line', null, { |
| email: email |
| }); |
| updateWidgets('contacts', null, { |
| email: email |
| }); |
| updateWidgets('top5', null, { |
| email: email |
| }); |
| updateWidgets('trends', null, { |
| email: email |
| }); |
| updateWidgets('relationship', null, { |
| email: email |
| }); |
| updateWidgets('viewpicker', null, { |
| email: email |
| }); |
| return globArgs.email = email; |
| }; |
| |
| treemap = function(json, state) { |
| var catdata, cats, colors, dates, div, echartLine, filled, i, lang, ld, len, len1, option, project, q, range, rect, ref, stack, type, u; |
| div = document.createElement('div'); |
| cats = new Array(); |
| dates = new Array(); |
| catdata = {}; |
| filled = { |
| areaStyle: { |
| type: 'default' |
| } |
| }; |
| if (json.widgetType) { |
| if (json.widgetType.chartType) { |
| type = json.widgetType.chartType; |
| } |
| if (json.widgetType.stack) { |
| stack = json.widgetType.stack; |
| } |
| if (json.widgetType.nofill) { |
| filled = null; |
| } |
| } |
| if (!json.widget.title || json.widget.title.length === 0) { |
| json.widget.title = 'Languages'; |
| } |
| if (!state.widget.div.style.height) { |
| div.style.minHeight = "900px"; |
| } else { |
| div.style.minHeight = "100%"; |
| } |
| if (state.widget.fullscreen) { |
| div.style.minHeight = (window.innerHeight - 100) + "px"; |
| } |
| state.widget.inject(div, true); |
| range = ""; |
| rect = div.getBoundingClientRect(); |
| theme.color = genColors(json.treemap.length + 1, 0.6, 0.5, true); |
| colors = genColors(json.treemap.length + 1, 0.6, 0.5, true); |
| theme.textStyle.fontSize = Math.max(12, window.innerHeight / 100); |
| echartLine = echarts.init(div, theme); |
| ld = []; |
| ref = json.treemap; |
| for (i = q = 0, len = ref.length; q < len; i = ++q) { |
| lang = ref[i]; |
| ld.push(lang); |
| for (u = 0, len1 = lang.length; u < len1; u++) { |
| project = lang[u]; |
| project.color = colors[i]; |
| project.itemStyle = { |
| normal: { |
| color: colors[i] |
| } |
| }; |
| } |
| } |
| option = { |
| title: { |
| text: json.widget.title, |
| left: 'center' |
| }, |
| legend: [ |
| { |
| x: 'center', |
| y: 'top', |
| data: ld |
| } |
| ], |
| tooltip: { |
| show: true, |
| feature: { |
| saveAsImage: { |
| show: true, |
| title: "Save Image" |
| } |
| }, |
| formatter: function(info) { |
| var aa, ref1, treePath, treePathInfo, value; |
| value = info.value; |
| treePathInfo = info.treePathInfo; |
| treePath = []; |
| for (i = aa = 1, ref1 = treePathInfo.length; 1 <= ref1 ? aa < ref1 : aa > ref1; i = 1 <= ref1 ? ++aa : --aa) { |
| treePath.push(treePathInfo[i].name); |
| } |
| return ['<div class="tooltip-title">' + treePath.join('/') + '</div>', 'Lines of Code: ' + value.pretty()].join(''); |
| } |
| }, |
| series: [ |
| { |
| name: json.widget.title, |
| type: 'treemap', |
| visibleMin: 1000, |
| label: { |
| show: true, |
| formatter: '{b}' |
| }, |
| itemStyle: { |
| normal: { |
| borderColor: '#fff' |
| } |
| }, |
| levels: [ |
| { |
| itemStyle: { |
| normal: { |
| borderColor: '#555', |
| borderWidth: 4, |
| gapWidth: 4 |
| } |
| } |
| }, { |
| colorSaturation: [0.3, 0.6], |
| itemStyle: { |
| normal: { |
| borderColorSaturation: 0.7, |
| gapWidth: 2, |
| borderWidth: 2 |
| } |
| } |
| } |
| ], |
| data: json.treemap |
| } |
| ] |
| }; |
| return echartLine.setOption(option = option); |
| }; |
| |
| trendBox = function(icon, count, title, desc) { |
| var cdiv, codiv, div, h3, i, icons, idiv, p; |
| icons = { |
| comment: 'fa-comments-o', |
| down: 'fa-sort-amount-desc', |
| up: 'fa-sort-amount-asc', |
| check: 'fa-check-square-o', |
| caret: 'fa-caret-square-o-right', |
| spin: 'fa-spin fa-cog' |
| }; |
| div = document.createElement('div'); |
| div.setAttribute("class", "animated flipInY col-lg-3 col-md-3 col-sm-6 col-xs-12"); |
| cdiv = document.createElement('div'); |
| cdiv.setAttribute("class", "tile-stats"); |
| cdiv.style.width = "100%"; |
| idiv = document.createElement('div'); |
| idiv.setAttribute("class", "icon"); |
| i = document.createElement('i'); |
| i.setAttribute("class", "fa " + (icons[icon] || 'fa-comments-o')); |
| idiv.appendChild(i); |
| cdiv.appendChild(idiv); |
| codiv = document.createElement('div'); |
| codiv.setAttribute("class", "count"); |
| codiv.appendChild(document.createTextNode(count)); |
| cdiv.appendChild(codiv); |
| h3 = document.createElement('h4'); |
| h3.appendChild(document.createTextNode(title)); |
| cdiv.appendChild(h3); |
| p = document.createElement('p'); |
| p.appendChild(document.createTextNode(desc)); |
| cdiv.appendChild(p); |
| div.appendChild(cdiv); |
| return div; |
| }; |
| |
| trend = function(json, state) { |
| var data, diff, icon, key, linediff, ref, results, tb, wipe; |
| console.log(state.widget.args.source); |
| if (json.trends) { |
| wipe = true; |
| ref = json.trends; |
| results = []; |
| for (key in ref) { |
| data = ref[key]; |
| linediff = ""; |
| icon = 'up'; |
| if (data.before > 0 && data.after > 0) { |
| diff = (data.after - data.before) / (data.before || 1); |
| if (diff >= 0) { |
| linediff = "Up " + Math.floor(diff * 100) + "% since last period"; |
| } else { |
| linediff = "Down " + Math.floor(diff * 100) + "% since last period"; |
| icon = 'check'; |
| } |
| } |
| tb = trendBox(icon, data.after.pretty(), data.title, linediff); |
| state.widget.inject(tb, wipe); |
| results.push(wipe = false); |
| } |
| return results; |
| } |
| }; |
| |
| newview = []; |
| |
| saveview = function(id) { |
| var publicView, view, viewname; |
| if (!id) { |
| if (get('viewname').value === '') { |
| alert('Please enter a name for this view!'); |
| return; |
| } |
| newview = []; |
| $("[datatype=source]").each(function() { |
| var pid, sel; |
| pid = $(this).attr('id'); |
| sel = $(this).attr('selected') || "blorp"; |
| if (sel === "selected") { |
| return newview.push(pid); |
| } |
| }); |
| viewname = get('viewname').value; |
| publicView = false; |
| if (get('public')) { |
| publicView = get('public').checked; |
| } |
| view = { |
| id: 'makeone', |
| name: viewname, |
| sources: newview, |
| "public": publicView |
| }; |
| return put('views', view, null, function() { |
| return window.setTimeout(function() { |
| return location.href = '?page=views'; |
| }, 1500); |
| }); |
| } else { |
| view = { |
| id: id, |
| sources: newview |
| }; |
| return patch('views', view, null, function() { |
| return window.setTimeout(function() { |
| return location.href = '?page=views'; |
| }, 1500); |
| }); |
| } |
| }; |
| |
| rmview = function(id) { |
| return xdelete('views', { |
| id: id |
| }, null, function() { |
| return window.setTimeout(function() { |
| return location.href = '?page=views'; |
| }, 1500); |
| }); |
| }; |
| |
| newview = []; |
| |
| currentSources = {}; |
| |
| filterView = function(val) { |
| var me, re, results, source, url; |
| re = new RegExp(val, 'i'); |
| newview = []; |
| results = []; |
| for (source in currentSources) { |
| url = currentSources[source]; |
| me = get(source); |
| me.removeAttribute('selected'); |
| me.style.background = "none"; |
| me.style.color = "#000"; |
| if (val.length > 0) { |
| me.style.display = 'none'; |
| } else { |
| me.style.display = 'block'; |
| } |
| if (val.length > 0 && url.match(re)) { |
| me.setAttribute("selected", "true"); |
| me.style.background = "#4B8"; |
| me.style.color = "#FFF"; |
| results.push(me.style.display = 'block'); |
| } else { |
| results.push(void 0); |
| } |
| } |
| return results; |
| }; |
| |
| manageviews = function(json, state) { |
| var aa, btn, h3, h4, inp, len, len1, len2, newdiv, noviews, obj, p, popdiv, q, ref, ref1, ref2, ref3, ref4, sdiv, source, u, view; |
| obj = mk('div'); |
| p = mk('p'); |
| app(p, txt("Views allow you to quickly set up a group of sources to view as a sub-organisation, much like tags, but faster.")); |
| app(obj, p); |
| h3 = mk('h3'); |
| noviews = json.views.length || 0; |
| app(h3, txt("You currently have " + noviews + " view" + (noviews === 1 ? '' : 's') + " in your database ")); |
| btn = mk('input'); |
| set(btn, 'type', 'button'); |
| set(btn, 'class', 'btn btn-success'); |
| set(btn, 'value', 'Create a new view'); |
| set(btn, 'onclick', 'get("newdiv").style.display = "block"; this.style.display = "none";'); |
| app(h3, btn); |
| app(obj, h3); |
| newdiv = mk('div'); |
| set(newdiv, 'id', 'newdiv'); |
| newdiv.style.display = "none"; |
| json.sources.sort(function(a, b) { |
| return (a.type === b.type ? (a.sourceURL > b.sourceURL ? 1 : -1) : (b.type < a.type ? 1 : -1)); |
| }); |
| inp = mk('input'); |
| set(inp, 'type', 'text'); |
| set(inp, 'id', 'viewname'); |
| app(newdiv, txt("Name your new view: ")); |
| app(newdiv, inp); |
| app(newdiv, mk('br')); |
| if (userAccount.userlevel === 'admin' || (ref = userAccount.defaultOrganisation, indexOf.call(userAccount.ownerships, ref) >= 0)) { |
| inp = mk('input'); |
| set(inp, 'type', 'checkbox'); |
| set(inp, 'id', 'public'); |
| app(newdiv, txt("Make view public (global): ")); |
| app(newdiv, inp); |
| app(newdiv, mk('br')); |
| } |
| inp = mk('input'); |
| set(inp, 'type', 'text'); |
| set(inp, 'id', 'viewfilter'); |
| set(inp, 'oninput', "filterView(this.value)"); |
| app(newdiv, txt("Filter-select: ")); |
| app(newdiv, inp); |
| app(newdiv, mk('i', {}, "You can use the filter-select to quickly mark sources based on a regex. Type in 'foo' to select all sources matching 'foo' etc.")); |
| app(newdiv, mk('br')); |
| app(newdiv, txt("Select the sources you wish to add to this view below:")); |
| app(newdiv, mk('br')); |
| btn = mk('input'); |
| set(btn, 'type', 'button'); |
| set(btn, 'class', 'btn btn-danger'); |
| set(btn, 'value', 'Save view'); |
| set(btn, 'onclick', 'saveview();'); |
| app(newdiv, btn); |
| ref1 = json.sources; |
| for (q = 0, len = ref1.length; q < len; q++) { |
| source = ref1[q]; |
| currentSources[source.sourceID] = source.sourceURL; |
| sdiv = mk('div'); |
| set(sdiv, 'id', source.sourceID); |
| set(sdiv, 'datatype', 'source'); |
| sdiv.style.cursor = 'pointer'; |
| sdiv.style.margin = "3px"; |
| sdiv.style.border = "1px solid #666"; |
| sdiv.style.color = "#000"; |
| sdiv.addEventListener("click", function() { |
| var selected, w; |
| w = findWidget(this.getAttribute('widget')); |
| selected = this.getAttribute("selected"); |
| if (selected && selected === "true") { |
| this.style.background = "none"; |
| this.style.color = "#000"; |
| set(this, 'selected', 'false'); |
| } else { |
| this.style.background = "#4B8"; |
| this.style.color = "#FFF"; |
| set(this, 'selected', 'true'); |
| } |
| return newview = []; |
| }); |
| app(sdiv, txt(source.sourceURL)); |
| app(newdiv, sdiv); |
| } |
| btn = mk('input'); |
| set(btn, 'type', 'button'); |
| set(btn, 'class', 'btn btn-danger'); |
| set(btn, 'value', 'Save view'); |
| set(btn, 'onclick', 'saveview();'); |
| app(newdiv, btn); |
| app(obj, newdiv); |
| ref2 = json.views; |
| for (u = 0, len1 = ref2.length; u < len1; u++) { |
| view = ref2[u]; |
| popdiv = mk('div'); |
| popdiv.style.paddingLeft = "10px"; |
| popdiv.style.margin = "3px"; |
| popdiv.style.borderRadius = "4px"; |
| h4 = mk('h4'); |
| app(h4, txt(view.name + " - " + view.sourceList.length + " sources")); |
| popdiv.style.border = "1px solid #333"; |
| popdiv.style.background = "#323234"; |
| h4.style.display = "inline-block"; |
| app(popdiv, h4); |
| btn = mk('input'); |
| set(btn, 'type', 'button'); |
| set(btn, 'class', 'btn btn-warning'); |
| set(btn, 'value', 'Edit view'); |
| set(btn, 'onclick', "get('" + view.id + "').style.display = (get('" + view.id + "').style.display == 'block') ? 'none' : 'block'"); |
| btn.style.marginLeft = "20px"; |
| btn.style.padding = "2px"; |
| app(popdiv, btn); |
| btn = mk('input'); |
| set(btn, 'type', 'button'); |
| set(btn, 'class', 'btn btn-danger'); |
| set(btn, 'value', 'Delete view'); |
| set(btn, 'onclick', 'rmview("' + view.id + '");'); |
| btn.style.marginLeft = "20px"; |
| btn.style.padding = "2px"; |
| app(popdiv, btn); |
| btn = mk('input'); |
| set(btn, 'type', 'button'); |
| set(btn, 'class', 'btn btn-success'); |
| set(btn, 'value', 'Save changes'); |
| set(btn, 'onclick', 'saveview("' + view.id + '");'); |
| btn.style.marginLeft = "20px"; |
| btn.style.padding = "2px"; |
| app(popdiv, btn); |
| h4.style.color = "#FFA"; |
| h4.style.cursor = 'pointer'; |
| set(h4, 'onclick', "get('" + view.id + "').style.display = (get('" + view.id + "').style.display == 'block') ? 'none' : 'block'"); |
| newdiv = mk('div'); |
| set(newdiv, 'id', view.id); |
| newdiv.style.display = "none"; |
| inp = mk('input'); |
| set(inp, 'type', 'text'); |
| set(inp, 'id', 'viewname'); |
| app(newdiv, txt("Select the sources you wish to have in this view below:")); |
| ref3 = json.sources; |
| for (aa = 0, len2 = ref3.length; aa < len2; aa++) { |
| source = ref3[aa]; |
| sdiv = mk('div'); |
| set(sdiv, 'id', view.id + "_" + source.sourceID); |
| set(sdiv, 'datatype', view.id); |
| sdiv.style.cursor = 'pointer'; |
| sdiv.style.margin = "3px"; |
| sdiv.style.border = "1px solid #666"; |
| sdiv.style.color = "#000"; |
| if (ref4 = source.sourceID, indexOf.call(view.sourceList, ref4) >= 0) { |
| sdiv.style.background = "#4B8"; |
| sdiv.style.color = "#FFF"; |
| set(sdiv, 'selected', 'selected'); |
| } else { |
| set(sdiv, 'selected', 'false'); |
| } |
| sdiv.addEventListener("click", function() { |
| var selected, vid; |
| selected = this.getAttribute("selected"); |
| vid = this.getAttribute("datatype"); |
| if (selected && selected === "selected") { |
| this.style.background = "none"; |
| this.style.color = "#000"; |
| set(this, 'selected', 'false'); |
| } else { |
| this.style.background = "#4B8"; |
| this.style.color = "#FFF"; |
| set(this, 'selected', 'selected'); |
| } |
| newview = []; |
| return $("[datatype=" + vid + "]").each(function() { |
| var pid, sel; |
| pid = $(this).attr('id').split(/_/)[1]; |
| sel = this.getAttribute("selected"); |
| if (sel === 'selected') { |
| return newview.push(pid); |
| } |
| }); |
| }); |
| app(sdiv, txt(source.sourceURL)); |
| app(newdiv, sdiv); |
| } |
| btn = mk('input'); |
| set(btn, 'type', 'button'); |
| set(btn, 'class', 'btn btn-success'); |
| set(btn, 'value', 'Save view'); |
| set(btn, 'onclick', 'saveview("' + view.id + '");'); |
| app(newdiv, btn); |
| app(obj, popdiv); |
| app(obj, newdiv); |
| } |
| return state.widget.inject(obj, true); |
| }; |