rbrindley: branch rbrindley/features_revamp r4742 - /team/rbrindley/features_...

SVN commits to the Asterisk-GUI project asterisk-gui-commits at lists.digium.com
Thu Apr 16 14:18:28 CDT 2009


Author: rbrindley
Date: Thu Apr 16 14:18:24 2009
New Revision: 4742

URL: http://svn.digium.com/svn-view/asterisk-gui?view=rev&rev=4742
Log:

- added all major javascript functions for the call features page


Modified:
    team/rbrindley/features_revamp/config/js/features2.js

Modified: team/rbrindley/features_revamp/config/js/features2.js
URL: http://svn.digium.com/svn-view/asterisk-gui/team/rbrindley/features_revamp/config/js/features2.js?view=diff&rev=4742&r1=4741&r2=4742
==============================================================================
--- team/rbrindley/features_revamp/config/js/features2.js (original)
+++ team/rbrindley/features_revamp/config/js/features2.js Thu Apr 16 14:18:24 2009
@@ -16,19 +16,155 @@
  * the GNU General Public License Version 2. See the LICENSE file
  * at the top of the source tree.
  */
-var enabled_apps;
 var exten_conf;
 var feat_conf;
+var gui_conf;
 var amap_table = $('#application_map_list tbody');
+var amap_orig_name;
+var vals = {};
+var dial_options;
+var dial_options_list = ['t', 'T', 'h', 'H', 'k', 'K'];
 
 /**
  * function to edit options
  * @param obj the DOM object
  */
 var edit = function(obj) {
-	this.vals[obj.attr('id')] = obj.val();
-	updateMsg(obj, 'edit');
-};
+	vals[obj.attr('id')] = obj.val();
+	if (typeof edit_funcs[obj.attr('id')] !== 'function') {
+		top.log.error('edit: edit_funcs["' + obj.attr('id') + '"] is not a function.');
+		updateMsg(obj, 'error', 'Error: Edit function was not found.');
+		return false;
+	}
+
+	try {
+		edit_funcs[obj.attr('id')](obj.val());
+		updateMsg(obj, 'edit');
+	} catch(e) {
+		switch (e.name) {
+		case 'ShouldRemoveException':
+			updateMsg(obj, 'error', 'Error: Should be removed instead.');
+		default:
+			updateMsg(obj, 'error', e.message);
+		}
+	}
+};
+
+/**
+ * object to hold all the (asterisk) editing/removing functions.
+ * This is done instead of generalizing them into sectioned objects
+ * because the layout/sections/organization may change.
+ * NOTE: only dial options use remove_funcs, removing for the others
+ * is just their edit_func with '' as the val
+ */
+var edit_funcs = {};
+var remove_funcs = {};
+
+edit_funcs['feature_featuredigittimeout'] = function(val) {
+	/* lets validate the val */
+	validate(val, {num: true, positive: true});
+
+	/* kk, all good, now update asterisk and go */
+	return sendUpdate({cxt: 'general', name: 'featuredigittimeout', val: val});
+};
+
+edit_funcs['parkext'] = function(val) {
+	/* lets validate */
+	validate(val, {num: true, positive: true, extens: true});
+
+	/* kk, all good, now update asterisk and go */
+	return sendUpdate({cxt: 'general', name: 'parkext', val: val});
+};
+
+edit_funcs['parkpos'] = function(val) {
+	/* validate special format */
+	if (!val.match(/[0-9][0-9]*\-[0-9][0-9]*/)) {
+		throw TypeError('Invalid: Please use "<num>-<num>" format');
+	}
+
+	/* lets split */
+	var splits = val.split('-');
+	var pos_start = parseInt(splits[0], 10);
+	var pos_end = parseInt(splits[1], 10);
+
+	/* now lets validate the start and end */
+	validate(pos_start, {num: true, positive: true});
+	validate(pos_end, {num: true, positive: true});
+
+	/* we need to do a special validate for extens */
+	gui_conf = context2json({
+		filename: 'guipreferences.conf',
+		context: 'general',
+		usf: 1
+	});
+	var prefs = {ue: 'User Extensions', mm: 'Conference Extensions', qe: 'Queue Extensions', vme: 'Voicemail Extensions', rge: 'Ring Group Extensions', vmg: 'Voicemail Group Extensions'};
+	for (pref in prefs) {
+		if (!prefs.hasOwnProperty(pref)) {
+			continue;
+		}
+
+		var start = gui_conf[pref + '_start'];
+		var end = gui_conf[pref + '_end'];
+
+		if ((pos_start >= start && pos_start <= end) || (pos_end >= start && pos_end <= end) || (pos_start < start && pos_end >= start)) {
+			top.log.warn('edit_funcs[\'parkext\']: conflicts with ' + pref + '.');
+			throw RangeError('Invalid: Conflicts with ' + prefs[pref] + ' range, ' + start + '-' + end);
+		}
+	}
+
+	/* kk, all good, now update asterisk and go */
+	return sendUpdate({cxt: 'general', name: 'parkpos', val: val});
+}
+
+edit_funcs['parkingtime'] = function(val) {
+	/* lets validate */
+	validate(val, {num: true, positive: true});
+
+	/* kk, all good, now update asterisk and go */
+	return sendUpdate({cxt: 'general', name: 'parkingtime', val: val});
+};
+
+edit_funcs['fmap_blindxfer'] = function(val) {
+	/* lets validate */
+	validate(val, {keypress: true});
+
+	/* kk, all good, now update asterisk and go */
+	return sendUpdate({cxt: 'featuremap', name: 'blindxfer', val: val});
+};
+
+edit_funcs['fmap_disconnect'] = function(val) {
+	/* lets validate */
+	validate(val, {keypress: true});
+
+	/* kk, all good, now update asterisk and go */
+	return sendUpdate({cxt: 'featuremap', name: 'disconnect', val: val});
+};
+
+edit_funcs['fmap_atxfer'] = function(val) {
+	/* lets validate */
+	validate(val, {keypress: true});
+
+	/* kk, all good, now update asterisk and go */
+	return sendUpdate({cxt: 'featuremap', name: 'atxfer', val: val});
+};
+
+edit_funcs['fmap_parkcall'] = function(val) {
+	/* lets validate */
+	validate(val, {keypress: true});
+
+	/* kk, all good, now update asterisk and go */
+	return sendUpdate({cxt: 'featuremap', name: 'parkcall', val: val});
+};
+
+/* dynamically define all the dial options edit/remove funcs since there the same */
+for (var i=0; i<dial_options_list.length; i++) {
+	edit_funcs['dial_'+dial_options_list[i]] = function(val) {
+		top.pbx.dial_options.add(val);
+	}
+	remove_funcs['dial_'+dial_options_list[i]] = function(val) {
+		top.pbx.dial_options.remove(val);
+	}
+}
 
 /**
  * function to load options
@@ -40,14 +176,14 @@
 		usf: 1
 	});
 
-	var dial_opts = exten_conf['DIALOPTIONS'] || '';
+	var dial_options = exten_conf['DIALOPTIONS'] || '';
 
 	if (exten_conf['FEATURES'] && exten_conf['FEATURES'].length) {
-		enabled_apps = exten_conf['FEATURES'].split('#');
+		amap_enabled = exten_conf['FEATURES'].split('#');
 	}
 
 	/* set all the enabled dial options to checked */
-	dial_opts = dial_opts.split('');
+	dial_opts = dial_options.split('');
 	for (var i=0; i<dial_opts.length; i++) {
 		$('#dial_'+dial_opts[i]).attr('checked', 'checked').parents('.feature').removeClass('disabled');
 	}
@@ -115,9 +251,12 @@
 }
 
 var listAmap = function(name) {
+	/* is it new or not? */
 	if (name) {
+		/* list an existing amap */
 		var amap_fields = feat_conf['applicationmap'][name].split(',');
 	} else {
+		/* set a new amap default values */
 		name = '';
 		var amap_fields = ['', 'self', '', ''];
 	}
@@ -127,7 +266,11 @@
 	}
 
 	var row = $('#application_map_list > tbody > tr.template').clone();
-	row.find('.enabled :checkbox').attr('checked', (enabled_apps.contains(name)?true:false));
+	/* only set id if its an existing amap */
+	if (name !== '') {
+		row.attr('id', 'amap_' + name);
+	}
+	row.find('.enabled :checkbox').attr('checked', (amap_enabled.contains(name)?true:false));
 	row.find('.name :text').attr('value', name);
 	row.find('.digits :text').attr('value', amap_fields[0]);
 	row.find('.app_name :text').attr('value', amap_fields[2]);
@@ -143,31 +286,270 @@
 	listAmap('');
 };
 
+var editAmap = function(obj) {
+	var vali = '';
+	var resp;
+
+	/* get the variables */
+	obj = obj.parents('tr');
+	var enabled = obj.find('.enabled > input').attr('checked');
+	var name = obj.find('.name > :text').val();
+	var digits = obj.find('.digits > :text').val();
+	var active = obj.find('.active option:selected').val();
+	var app_name = obj.find('.app_name :text').val();
+	var app_args = obj.find('.app_args :text').val();
+
+	if (!validateAmap(obj, name, digits, app_name)) {
+		return false;
+	}
+
+	/* generate the applicationmap string */
+	var value = [digits, active, app_name, app_args].join();
+
+	/* time to upload to Asterisk */
+	var actions = listOfSynActions('features.conf');
+	if (obj.attr('id').substring(5) !== name) {
+		actions.new_action('delete', 'applicationmap', obj.attr('id').substring(5), '');
+	}
+	actions.new_action('update', 'applicationmap', name, value);
+
+	resp = actions.callActions();
+	if (!resp.contains('Response: Success')) {
+		top.log.error('editAmap: error updating features.conf');
+		return false;
+	}
+
+	if (enabled) {
+		actions.clearActions('extensions.conf');
+		resp = '';
+
+		if (obj.attr('id') !== '') {
+			amap_enabled.splice(amap_enabled.indexOf(obj.attr('id').substring('5'), 1));
+		}
+		amap_enabled.push(name);
+		actions.new_action('update', 'globals', 'FEATURES', amap_enabled.join('#'));
+		
+		resp = actions.callActions();
+		if (!resp.contains('Response: Success')) {
+			top.log.error('editAmap: error updating features.conf');
+			return false;
+		}
+	}
+
+	obj.attr('id', 'name');
+};
+
+var removeAmap = function(obj) {
+	/* if this doesn't have an id, its most likely a 'new, unsaved' amap */
+	if (!obj.parents('tr').attr('id')) {
+		obj.parents('tr').queue(function() {
+			$(this).fadeOut(500);
+			$(this).dequeue();
+		});
+		obj.parents('tr').queue(function() {
+			$(this).remove();
+			$(this).dequeue();
+		});
+		return true;
+	}
+	var name = obj.parents('tr').attr('id').substring('5'); /* amap_XXXNAMEXXX */
+	var actions = new listOfSynActions('extensions.conf');
+	var resp;
+
+	if (amap_enabled.contains(name)) {
+		amap_enabled.splice(amap_enabled.indexOf(name), 1);
+		actions.new_action('update', 'globals', 'FEATURES', amap_enabled.join('#'));
+
+		resp = actions.callActions();
+		if (!resp.contains('Response: Success')) {
+			top.log.error('removeAmap: Error updating extensions.conf');
+			return false;
+		}
+	}
+	actions.clearActions('features.conf');
+
+	actions.new_action('delete', 'applicationmap', name, '');
+
+	resp = actions.callActions();
+	if (!resp.contains('Response: Success')) {
+		top.log.error('removeAmap: Error updating features.conf');
+		return false;
+	}
+
+	obj.parents('tr').queue(function() {
+		$(this).fadeOut(500);
+		$(this).dequeue();
+	});
+	obj.parents('tr').queue(function() {
+		$(this).remove();
+		$(this).dequeue();
+	});
+};
+
+var validateAmap = function(obj, name, digits, app_name) {
+	/* lets validate all the variables before we send */
+	try {
+		vali = 'name';
+		validate(name, {notnull: true, str: true, aststr: true});
+		vali = 'digits';
+		validate(digits, {notnull: true, num: true});
+		vali = 'app_name';
+		validate(app_name, {notnull: true, str: true});
+	} catch(e) {
+		obj.find('td.'+vali+' input').focus().addClass('error');
+		top.log.error(e.message);
+		return false;
+	}
+
+	obj.find('input').removeClass('error');
+	return true;
+}
+
 /**
  * function to removing options
  * @param obj the DOM object
  */
 var remove = function(obj) {
-	this.vals[obj.attr('id')] = obj.val();
-	updateMsg(obj, 'remove');
-};
+	vals[obj.attr('id')] = obj.val();
+	if (obj.attr('type') === 'checkbox') {
+		if (typeof remove_funcs[obj.attr('id')] !== 'function') {
+			top.log.error('remove: remove_funcs["' + obj.attr('id') + '"] is not a function.');
+			updateMsg(obj, 'error', 'Error: Remove function was not found.');
+			return false;
+		}
+	} else {
+		if (typeof edit_funcs[obj.attr('id')] !== 'function') {
+			top.log.error('remove: edit_funcs["' + obj.attr('id') + '"] is not a function.');
+			updateMsg(obj, 'error', 'Error: Remove function was not found.');
+			return false;
+		}
+	}
+
+	try {
+		if (obj.attr('type') === 'checkbox') {
+			remove_funcs[obj.attr('id')](obj.val());
+		} else {
+			edit_funcs[obj.attr('id')]('');
+		}
+
+		updateMsg(obj, 'remove');
+	} catch(e) {
+		switch (e.name) {
+		default:
+			updateMsg(obj, 'error', e.message);
+		}
+	}
+};
+
+/**
+ * sends updates to Asterisk.
+ * @param cxt variable's context.
+ * @param name variable name.
+ * @param val variable value.
+ * @throws CommunicationError.
+ * @return boolean of success.
+ */
+var sendUpdate = function(params) {
+	if (!params.cxt || !params.name) {
+		top.log.error('sendUpdate: params.cxt or params.name is undefined.');
+		throw TypeError('Error: params.cxt or params.name is undefined.');
+	}
+
+	var actions = listOfSynActions('features.conf');
+	actions.new_action('update', params.cxt, params.name, params.val);
+	var resp = actions.callActions();
+	if (!resp.contains('Response: Success')) {
+		top.log.error('sendUpdate: error updating features.conf.');
+		throw CommunicationError('Error: Unable to update features.conf.');
+	}
+
+	return true;
+}
 
 /**
  * function to show update mesgs
  * @param obj the DOM object
  * @param msg the msg to display
  */
-var updateMsg = function(obj, type) {
+var updateMsg = function(obj, type, err) {
 	var type = type || '';
+	var err = err || '';
 	switch(type) {
 	case 'edit':
-		var clr = '#aeffae';
+		obj.siblings('.update').hide();
+		obj.parents('.feature').effect('highlight', {color: '#aeffae'}, 1000);
 		break;
 	case 'error':
-		var clr = 'orange';
+		obj.siblings('.update').html(err);
+		obj.siblings('.update').show();
 		break;
 	default:
-		var clr = '#ffaeae';
-	}
-	obj.parents('.feature').effect('highlight', {color: clr}, 1000);
-};
+		obj.siblings('.update').hide();
+		obj.parents('.feature').effect('highlight', {color: '#ffaeae'}, 1000);
+	}
+};
+
+var validate = function(val, chks) {
+	/* does val exist? */
+	if (chks.notnull && (typeof val === 'undefined' || val === '' || val === null)) {
+		top.log.error('validate: val is not defined.');
+		throw TypeError('Invalid: This cannot be empty.');
+	}
+
+	/* make sure val is a num */
+	if (chks.num && isNaN(val)) {
+		top.log.error('validate: val needs to be a number.');
+		throw TypeError('Invalid: This needs to be a number.');
+	}
+
+	/* is val a string? */
+	if (chks.str && typeof val !== 'string') {
+		top.log.error('validate: val needs to be a string.');
+		throw TypeError('Invalid: This needs to be a string.');
+	}
+
+	/* make sure its 0 or more */
+	if (chks.positive && val < 0) {
+		top.log.warn('validate: val needs to be 0 or greater.');
+		throw RangeError('Invalid: This needs to be 0 or greater.');
+	}
+
+	/* lets make sure the exten doesn't conflict with any extension ranges */
+	if (chks.extens) {
+		gui_conf = context2json({
+			filename: 'guipreferences.conf',
+			context: 'general',
+			usf: 1
+		});
+		var prefs = {ue: 'User Extensions', mm: 'Conference Extensions', qe: 'Queue Extensions', vme: 'Voicemail Extensions', rge: 'Ring Group Extensions', vmg: 'Voicemail Group Extensions'};
+		for (pref in prefs) {
+			if (!prefs.hasOwnProperty(pref)) {
+				continue;
+			}
+
+			var start = gui_conf[pref + '_start'];
+			var end = gui_conf[pref + '_end'];
+
+			if (val >= start && val <= end) {
+				top.log.warn('validate: conflicts with ' + pref + '.');
+				throw RangeError('Invalid: Conflicts with ' + prefs[pref] + ' range, ' + start + '-' + end);
+			}
+		}
+	}
+
+	if (chks.keypress && val !== '' && !val.match(/[0-9#*][0-9#*]*/)) {
+		top.log.error('validate: val should only contain 0-9, #, or *.');
+		throw TypeError('Invalid: This should only contain 0-9, #, or *.');
+	}
+
+	if (chks.aststr && !val.match(/[a-zA-Z0-9_-][a-zA-Z0-9_-]*/)) {
+		top.log.error('validate: val should only contain a-z, A-Z, 0-9, _, or -.');
+		throw TypeError('Invalid: This should only contain a-z, A-Z, 0-9, _, or -');
+	}
+};
+
+/********* EXCEPTIONS **********/
+var CommunicationError = function(msg) {
+	this.name = "CommunicationError";
+	this.msg = msg || "An error occurred while communicating with Asterisk.";
+};




More information about the asterisk-gui-commits mailing list