nut/docs/website/scripts/nut_jquery.js
2013-11-24 16:00:12 +01:00

577 lines
10 KiB
JavaScript

var NUT = {
// UPS table DOM ids
listID: "#ups_list",
listBodyID: "#ups_list_body",
// Field names
fields: [
"manufacturer",
"device-type",
"support-level",
"model",
"comment",
"driver"
],
// Actual HTML table columns
columns: [
[ "manufacturer" ],
[ "model", "comment" ],
[ "driver" ],
[ "support-level" ],
],
// driver => connection type mappings
driverMap: function(driver) {
// Try not to catch "usb" across a word boundary:
if (driver.match(/_usb|usbserial|usbhid-ups/))
return "USB";
// TODO: what about IPMI/powerman-pdu?
if (driver.match(/snmp-ups|netxml-ups/))
return "Network";
return "Serial";
},
// Support level => CSS class mappings
supportLevelClasses: {
0: "",
1: "red",
2: "orange",
3: "yellow",
4: "blue",
5: "green"
},
tableCache: false,
// Parse GET parameters from window url and return them as a hash
// The call format is:
// stable-hcl.html?<filter name>=<filter value>
// Refer to docs/stable-hcl.txt for examples
parseGetParameters: function() {
var url = window.location.href;
url = url.replace(/#$/, "");
var fieldPos = url.indexOf("?");
var get = {};
if (fieldPos > -1) {
var fileName = url.substring(0, fieldPos);
var getList = url.substring(fieldPos + 1).split("&");
for (var i = 0; i < getList.length; i++) {
var getField = getList[i].split("=");
key = unescape(getField[0]).toLowerCase();
value = unescape(getField[1]);
// just in case there are any old links out there.
if (key === "manufacturer" && value === "Tripp-Lite") {
value = "Tripp Lite";
}
get[key] = value;
}
}
return get;
},
// UPS filter renderers by data column index
filterRenderers: {
"support-level": function(value) {
var result = [];
for (var i = 0; i < value; i++)
result.push("*");
return result.join("");
},
"driver": function(value) {
return this.driverMap(value);
},
"device-type": function(value) {
var map = {
"pdu": "Power Distribution Unit",
"ups": "Uninterruptible Power Supply",
"scd": "Solar Controller Device"
}
return map[value];
}
},
// Specific filter handlers
filterHandlers: {
// Filter functions:
// @param {string} value value to filter
// @param {array} row raw data fields
// @return {boolean} true if value passes the filter, false otherwise
"driver": function(value, row) {
var driver = row[this.fields.indexOf("driver")];
if (this.driverMap(driver) == value)
return true;
return false;
},
"support-level": function(value, row) {
var level = row[this.fields.indexOf("support-level")];
if (level >= value)
return true;
return false;
}
},
// Returns rendered UPS data according to column index
// @param {integer} index
// @param {string} value
renderFilter: function(index, value) {
var renderer = this.filterRenderers[this.fields[index]];
if (typeof renderer == "function")
return renderer.call(this, value);
return value;
},
// Initialization method
init: function() {
this.initFilters();
this.sortUPSData(UPSData);
this.buildUPSList(UPSData);
this.buildFilters(UPSData);
var get = this.parseGetParameters();
for (var param in get) {
var filter = $("#"+param);
if (filter) {
filter.val(get[param]);
this.doFilter();
}
}
},
// Initialize filter filters references
initFilters: function() {
// Display filters fieldset hidden by default for user-agents not using javascript
$("#filters-set").show();
this.filters = {
"support-level": {
index: this.fields.indexOf("support-level"),
field: $("#support-level")
},
"device-type": {
index: this.fields.indexOf("device-type"),
field: $("#device-type")
},
"manufacturer": {
index: this.fields.indexOf("manufacturer"),
field: $("#manufacturer")
},
"model": {
index: this.fields.indexOf("model"),
field: $("#model")
},
"driver": {
index: this.fields.indexOf("driver"),
field: $("#connection")
}
}
},
// Sorts table data by manufacturer and driver
// @param {Object} data
sortUPSData: function(data) {
var mI = this.fields.indexOf("manufacturer"),
dI = this.fields.indexOf("driver");
data.sort(function(a, b) {
var toLower = function(ar) {
var res = ar.slice();
res.forEach(function(i, index) {
if (typeof i == "string")
res[index] = i.toLowerCase()
});
return res;
}
var c = toLower(a),
d = toLower(b);
return c[mI] == d[mI] ? c[dI] > d[dI] : c[mI] > d[mI];
});
},
// Builds UPS list from provided data
// @param {array} data
buildUPSList: function(data) {
var list = $(this.listBodyID);
// Initialize table cache
if (!this.tableCache)
this.tableCache = list.html();
// If we're rebuilding the original table, just use the one in cache
if (data == UPSData && this.tableCache) {
list.html(this.tableCache);
return;
}
list.empty();
// Bailout if no data
if (!data || data.length == 0)
return;
// Build rows
var cellHistory = [], rows = [];
var rowHistory = data[0][0];
var classes = [ "even", "odd" ],
manufIndex = this.fields.indexOf("manufacturer"),
currentClass = 0;
data.forEach(function(upsRow, rowIndex) {
if (upsRow[manufIndex] != rowHistory) {
currentClass = Number(!currentClass);
rowHistory = upsRow[manufIndex];
}
var cells = [];
// Build cells
this.columns.forEach(function(column, colIndex) {
var cellContent = [];
column.forEach(function(field) {
cellContent.push(upsRow[this.fields.indexOf(field)])
}, this);
cellContent = cellContent.join("<br />");
// Inspect the last cell on this column and increase row span if the current cell has the same content
var cH = cellHistory[colIndex];
if (column.indexOf("driver") == -1 && cH && cH.html == cellContent)
cH.rowSpan += 1;
else {
var cell = "";
if (column.indexOf("driver") != -1) {
cell = {
html: cellContent,
rowSpan: 1,
cls: this.supportLevelClasses[upsRow[this.fields.indexOf("support-level") || ""]]
};
} else {
cell = {
html: cellContent,
rowSpan: 1,
cls: classes[currentClass]
}
}
if (column.indexOf("support-level") != -1)
cell.cls += " hidden";
cells.push(cell);
cellHistory[colIndex] = cell;
}
}, this);
rows.push(cells);
}, this);
// Generate actual rows/cells tags
rows.forEach(function(r, index) {
r.forEach(function(c, index) {
r[index] = [ "<td class='", c.cls, "' rowspan='", c.rowSpan, "'>", c.html, "</td>" ].join("");
});
rows[index] = [ "<tr>", r.join(""), "</tr>" ].join("");
});
list.html(rows.join(""));
},
// Initialize filters event listeners
// @param {Object} data
buildFilters: function(data) {
for (var f in this.filters) {
var filter = this.filters[f];
this.populateCombo(data, filter);
filter.field.change(this.doFilter);
var op = $("#op-" + (filter.index));
if (op)
op.change(this.doFilter);
}
},
// Load data in filter combos
// @param {array} data
// @param {object} combo
// @param {integer} index
populateCombo: function(data, filter) {
var values = [];
var valueDict = {};
var combo = filter.field;
var oldValue = combo.val();
combo.html("<option value='-1'>---</option>");
// Special case for connection type
if (filter.field.attr("id") == "connection") {
[ "Serial", "USB", "Network" ].forEach(function(type) {
values.push([ type, type ]);
}, this);
} else {
data.forEach(function(row) {
var value = row[filter.index];
if (value != "" && !valueDict[value]) {
values.push([ value, this.renderFilter(filter.index, value) ]);
valueDict[value] = true;
}
}, this);
values = values.sort();
}
values.forEach(function(value) {
var option = $(document.createElement("option"));
option.val(value[0]);
option.text(value[1]);
combo.append(option);
}, this);
combo.val(oldValue);
},
// Apply selected filters on UPS list
doFilter: function() {
var initialRows = UPSData.slice();
var filteredRows = UPSData.slice();
// Applies a single filter on provided UPS data set
// @param {string} value
// @param {integer} index
// @param {array} data
// @returns {array} filtered data set
var applyFilter = function(value, index, data) {
var tmpData = [];
tmpData = data.slice();
tmpData.forEach(function(row, rowIndex) {
var field = row[index];
var handler = this.filterHandlers[this.fields[index]];
if (handler) {
if (!handler.apply(this, [ value, row ]))
data.splice(data.indexOf(row), 1);
} else if (row[index] != value)
data.splice(data.indexOf(row), 1);
}, this);
return data;
}
// Sequentially apply filters
for (var f in NUT.filters) {
var filter = NUT.filters[f];
var value = filter.field.val();
// Is filter active, i.e have the user picked a value in the filter combo
if (value != "-1") {
var opField = $("#op-" + filter.index);
filteredRows = applyFilter.apply(NUT, [ value, filter.index, filteredRows ]);
}
}
// Rebuild UPS list and combos according to filtered data
NUT.buildUPSList(filteredRows);
[ "manufacturer", "model", "driver" ].forEach(function(id) {
if (this.id != id)
this.populateCombo(filteredRows, this.filters[id]);
}, NUT);
},
resetCombos: function() {
for (var f in this.filters) {
var field = this.filters[f].field;
this.populateCombo(UPSData, this.filters[f]);
field.val("-1");
}
this.buildUPSList(UPSData);
}
}
if (typeof Array.prototype.indexOf != "function") {
Array.prototype.indexOf = function(elt) {
var i = 0;
while (i < this.length) {
if (this[i] == elt)
return i;
i++;
}
return -1;
}
}
if (typeof Array.prototype.forEach != "function") {
Array.prototype.forEach = function(cb, scope) {
for (var i = 0, n = this.length; i < n; i++) {
if (i in this)
cb.call(scope, this[i], i, this);
}
}
}
// Global initialization
$(function() {
NUT.init.call(NUT);
});