// this file provides shared javascript functions for all interface functions
// return a new json data store
// url - url to fetch data from
// fields - array of field names to use from url response
function newStore(url, fields)
{
return new Ext.data.JsonStore({
url: url,
root: 'results',
fields: fields
});
}
// generate a extjs grid. a checkbox column, a double click handler and 'Add' and 'Delete' buttons are added automatically.
// store - data store to use for grid content
// columns - array of column definitions to use
// dblclickUrl - url to hit when a row is double clicked. the id of the record (not column) is appended to the url
// addUrl - url to hit when the Add button is clicked.
// deleteUrl - url to hit when the Delete button is clicked. this url will be hit once for each row with the id of the selected
// record appended to it.
// includeFields - additional fields from the row to include with both, dblclickUrl and deleteUrl
// deleteMsg - optionally, a different message to display on delete
function newGrid(store, columns, dblclickUrl, addUrl, deleteUrl, includeFields, deleteMsg, title)
{
if ('undefined' != typeof deleteUrl) {
var sm = new Ext.grid.CheckboxSelectionModel();
columns = [sm].concat(columns);
}
var cm = new Ext.grid.ColumnModel(columns);
cm.defaultSortable = true;
cm.defaultWidth = 140;
var tbAdd = {
text: 'Add',
handler: function() {
window.location = addUrl;
}
};
var tbDelete = {
text: 'Delete',
handler: function() {
var msg = 'Are you sure you want to delete the selected item(s)?';
if ('undefined' != typeof deleteMsg) {
msg = deleteMsg;
}
Ext.MessageBox.confirm('Confirm', msg, function(btn, text) {
if ('yes' == btn) {
sm.getSelections().each(function(rec) {
// always add id to url
var url = deleteUrl + '&id=' + rec.data.id;
// add any optional fields
if ('undefined' != typeof includeFields) {
includeFields.each(function(field, i) {
if ('undefined' != typeof rec.data[field]) {
url += '&' + field + '=' + rec.data.type;
}
});
}
new Ajax.Request(url, {
method: 'get',
onSuccess: function(rs) {
store.remove(rec);
}
});
});
}
});
}
};
var tb = [];
if ('undefined' != typeof deleteUrl) {
tb.push(tbDelete);
}
if ('undefined' != typeof addUrl) {
tb.push(tbAdd);
}
var grid = new Ext.grid.GridPanel({
store: store,
cm: cm,
sm: sm,
width: 800,
height: 500,
stripRows: true,
trackMouseOver: true,
title: title,
//style: 'padding-bottom: 10px', // XXX this adds useless padding if contained in a frame
tbar: (0 < tb.size()) ? tb : undefined
});
if ('undefined' != typeof dblclickUrl) {
grid.on('rowdblclick', function(grid, i, e) {
var data = store.getAt(i).data;
// always add id to url
var url = dblclickUrl + '&id=' + data.id;
// add any optional fields
if ('undefined' != typeof includeFields) {
includeFields.each(function(field, i) {
if ('undefined' != typeof data[field]) {
url += '&' + field + '=' + data.type;
}
});
}
window.location = url;
});
}
return grid;
}
function newGridSimple(store, columns, title, dblclickUrl, style)
{
var cm = new Ext.grid.ColumnModel(columns);
cm.defaultSortable = true;
cm.defaultWidth = 140;
var grid = new Ext.grid.GridPanel({
store: store,
cm: cm,
width: 800,
height: 500,
stripRows: true,
trackMouseOver: true,
title: title,
style: style
});
if ('undefined' != typeof dblclickUrl) {
grid.on('rowdblclick', function(grid, i, e) {
var data = store.getAt(i).data;
var url = dblclickUrl + '&id=' + data.id;
if ('undefined' != typeof includeFields) {
includeFields.each(function(field, i) {
if ('undefined' != typeof data[field]) {
url += '&' + field + '=' + data.type;
}
});
}
window.location = url;
});
}
return grid;
}
// generates a extjs form.
// title - title of the form
// targetUrl - target url to hit when clicking Save button
// completedUrl - url to hit after targetUrl returned success = true
function newForm(title, targetUrl, completedUrl, buttonName)
{
Ext.form.Field.prototype.msgTarget = 'under';
var form = new Ext.FormPanel({
url: targetUrl,
method: 'get',
frame: true,
title: title,
bodyStyle: 'padding: 5px 5px 0',
width: 600,
defaultType: 'textfield',
buttons: [{
text: ('undefined' == typeof buttonName) ? 'Save' : buttonName,
handler: function() {
if (form.form.isValid()) {
form.form.submit({
waitMsg: 'Saving...',
failure: function(form, rs) {
Ext.MessageBox.alert('Errors', rs.result.message);
},
success: function(form, rs) {
var url = completedUrl;
Object.keys(rs.result).each(function(key, i) {
url += '&' + key + '=' + rs.result[key];
});
window.location = url;
}
});
} else {
Ext.MessageBox.alert('Errors', 'Please correct the errors noted.');
}
}
}
]
});
return form;
}
// generates a sub menu containing links.
// links - hash containing objects mapping a name to a url. Eg $H({'foo': 'bar'}) generates a link 'foo' pointing to 'bar'.
// ($H() is prototype's version of a 'hash')
function subMenu(links, font_size)
{
if ('undefined' != typeof font_size) {
var submenu = new Element('div', {style: 'float: left; width: 550px; font-size: ' + font_size + ';'});
} else {
var submenu = new Element('div', {style: 'float: left; width: 550px;'});
}
links.each(function(data, index) {
var linkClass = 'navbutton';
if (1 == links.size()) {
// if only one link, use rounded edges on both sides
linkClass += ' button4';
} else if (0 == index) {
// if first link, use rounded left edge
linkClass += ' button1';
} else if (links.size() - 1 == index) {
// if last link, use rounded right edge
linkClass += ' button3';
} else {
// if middle, use straight edges
if (12 > data[0].length) {
linkClass += ' button2';
} else {
linkClass += ' button2b';
}
}
if (window.location.search == data[1]) {
linkClass += ' navactive';
}
var link = new Element('a', { 'class': linkClass, href: data[1] }).update(data[0]);
submenu.appendChild(link);
}, links);
$('submenu').appendChild(submenu);
}
// generates provisioning submenu. add additional entries as required
function subMenuProvisioning()
{
subMenu($H({
'Customers': '?a=provisioning&b=show_customers'
}));
}
// generates monitor submenu.
function subMenuMonitoring()
{
subMenu($H({
'Access Points': '?a=monitoring&b=show_access_points',
'Customers': '?a=monitoring&b=show_customers',
'Network Map': '?a=monitoring&b=show_network_map',
'Network Overview': '?a=monitoring&b=show_network_overview',
'Towers': '?a=monitoring&b=show_towers'
}), '10px');
}
// adds additional verification types to extjs on load
Ext.onReady(function() {
Ext.apply(Ext.form.VTypes, {
// creates 'coordinaet' vtype for use by form elements
coordinate: function(value) {
return /^([\d.-]+,[\d.-]+)$/.test(value);
},
// message to display if coordinate() returns false
coordinateText: 'Coordinates must be in XX,YY format.',
coordinateMask: /[\d,.-]/,
ip_address: function(value) {
return /^([\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3})$/.test(value);
},
ip_addressText: 'IP address must be in XXX.XXX.XXX.XXX format.',
ip_addressMask: /[\d.]/,
hostmask: function(value) {
return /^([\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}\/[\d]{1,2})$/.test(value);
},
hostmaskText: 'Hostmask must be in XXX.XXX.XXX.XXX/YY format.',
hostmaskMask: /[\d.//]/,
account_number: function(value) {
return /^([\d]{4}-[\d]{7})$/.test(value);
},
account_numberText: 'Account number must be in XXXX-XXXXXXX format.',
account_numberMask: /[\d-]/,
zip: function(value) {
return /^([\d]{5})$/.test(value);
},
zipText: 'Zip code must be 5 digits.',
zipMask: /[\d]/,
phone_number: function(value) {
return /^(\d{3}[-]?){1,2}(\d{4})$/.test(value);
},
phone_numberText: 'Phone number must be in XXX-XXX-XXXX format.',
phone_numberMask: /[\d-]/,
mac_address: function(value) {
return /^([0-9A-Fa-f]{2}:?){5}[0-9A-Fa-f]{2}$/i.test(value);
},
mac_addressText: 'Please enter a valid MAC address',
mac_addressMask: /[0-9A-Fa-f:]/,
username: function(value) {
return /^([0-9A-Z_-]+)$/i.test(value);
},
usernameText: 'Username must only contain alphanumerics, - and _',
usernameMask: /[0-9A-Z_-]/i
});
});
function show(item)
{
item.enable().show();
if ('function' != typeof item.getEl() && item.getEl().up('.x-form-item')) {
item.getEl().up('.x-form-item').setDisplayed(true);
}
if ('object' == typeof item.items) {
item.items.each(function(component, i) {
component.enable();
});
}
}
function hide(item)
{
item.disable().hide();
if ('undefined' != typeof item.getEl() && item.getEl().up('.x-form-item')) {
item.getEl().up('.x-form-item').setDisplayed(false);
}
if ('object' == typeof item.items) {
item.items.each(function(component, i) {
component.disable();
});
}
}
function hideAll(items)
{
items.each(function(item, i) {
hide(item);
});
}
function showAll(items)
{
items.each(function(item, i) {
show(item);
});
}
// customer renderer for status column
function statusRenderer(value)
{
if (0 == value) {
return 'Offline';
} else {
return 'Online';
}
}
function addGroupButton(grid, returnUrl)
{
grid.getTopToolbar().push({
xtype: 'tbseparator'
});
grid.getTopToolbar().push({
text: 'Manage groups',
handler: function() {
var url = '?a=provisioning&b=update_group_devices&returnurl=' + escape(returnUrl) + '&devices=';
var go = false;
grid.getSelectionModel().getSelections().each(function(rec) {
url += rec.data['table'] + "|" + rec.data['id'] + ',';
go = true;
});
if (go) {
window.location = url.truncate(url.length - 1, '');
}
}
});
}
function onLoad(stores, callback)
{
stores.each(function(store) {
store.loaded = false;
store.on('load', function() {
this.loaded = true;
var done = true;
stores.each(function(store) {
if (!store.loaded) {
done = false;
}
});
if (done) {
callback();
}
});
});
}