diff --git a/src/apps/callflows/app.js b/src/apps/callflows/app.js
index 7cdcd6c..85368d5 100644
--- a/src/apps/callflows/app.js
+++ b/src/apps/callflows/app.js
@@ -10,7 +10,7 @@ define(function(require) {
'conference',
'device',
'directory',
- 'eavesdrop',
+ 'eavesdrop',
'faxbox',
'featurecodes',
'groups',
@@ -606,11 +606,16 @@ define(function(require) {
formattedData.extra.isShoutcast = false;
formattedData.extra.preflowCallflows = [];
+ var numbers,
+ patterns
_.each(formattedData.callflows, function(callflow) {
- if (callflow.featurecode === false && callflow.numbers && callflow.numbers.length && callflow.numbers.indexOf('no_match') < 0) {
+ numbers = callflow.numbers;
+ patterns = callflow.patterns;
+ if (callflow.featurecode === false
+ && (numbers.length > 0 || patterns.length > 0)) {
formattedData.extra.preflowCallflows.push({
id: callflow.id,
- friendlyName: callflow.name || callflow.numbers.toString()
+ friendlyName: callflow.name || numbers.concat(patterns).join(', ')
});
}
});
@@ -1023,19 +1028,20 @@ define(function(require) {
_.each(data.data, function(callflow) {
var formattedNumbers = _.map(callflow.numbers || '-', function(number) {
- return _.startsWith('+', number)
- ? monster.util.formatPhoneNumber(number)
- : number;
- }),
- listNumbers = formattedNumbers.toString(),
- isFeatureCode = callflow.featurecode !== false && !_.isEmpty(callflow.featurecode);
+ return _.startsWith('+', number)
+ ? monster.util.formatPhoneNumber(number)
+ : number;
+ });
+
+ var listNumbersAndPatterns = _.merge(formattedNumbers, callflow.patterns).join(', ');
+ var isFeatureCode = callflow.featurecode !== false && !_.isEmpty(callflow.featurecode);
if (!isFeatureCode) {
if (callflow.name) {
- callflow.description = listNumbers;
+ callflow.description = listNumbersAndPatterns;
callflow.title = callflow.name;
} else {
- callflow.title = listNumbers;
+ callflow.title = listNumbersAndPatterns;
}
formattedList.push(callflow);
@@ -1051,6 +1057,20 @@ define(function(require) {
return data;
},
+ callflowsGetModulesByNameInCallflow: function (flow, moduleName, resultArr) {
+ var self = this;
+ resultArr = resultArr || [];
+
+ if(flow.module === moduleName) {
+ resultArr.push(flow.data);
+ }
+
+ for(var k in flow.children) if(flow.children.hasOwnProperty(k)) {
+ self.callflowsGetModulesByNameInCallflow(flow.children[k], moduleName, resultArr);
+ }
+ return resultArr;
+ },
+
editCallflow: function(data) {
var self = this;
@@ -1078,14 +1098,28 @@ define(function(require) {
self.flow.name = callflow.name;
self.flow.contact_list = { exclude: 'contact_list' in callflow ? callflow.contact_list.exclude || false : false };
self.flow.caption_map = callflow.metadata;
-
- if (callflow.flow.module !== undefined) {
- self.flow.root = self.buildFlow(callflow.flow, self.flow.root, 0, '_');
- }
-
self.flow.numbers = callflow.numbers || [];
+ self.flow.patterns = callflow.patterns || [];
- self.repaintFlow();
+ var buildAndRepaintFlow = function () {
+ if (callflow.flow.module !== undefined) {
+ self.flow.root = self.buildFlow(callflow.flow, self.flow.root, 0, '_');
+ }
+ self.repaintFlow();
+ };
+
+ var callflowModulesInFlow = self.callflowsGetModulesByNameInCallflow(callflow.flow, 'callflow', []);
+ if(callflowModulesInFlow.length > 0) {
+ self.callflowsExtendMetadataOfCallflowModules(callflowModulesInFlow, function (callflows) {
+ for (var c in callflows) if (callflows.hasOwnProperty(c)) {
+ self.flow.caption_map[callflows[c].id].numbers = callflows[c].numbers;
+ self.flow.caption_map[callflows[c].id].patterns = callflows[c].patterns;
+ }
+ buildAndRepaintFlow();
+ })
+ } else {
+ buildAndRepaintFlow();
+ }
}
});
} else {
@@ -1098,6 +1132,48 @@ define(function(require) {
self.renderTools();
},
+ callflowsGetCallflow: function (id, callback) {
+ var self = this;
+
+ self.callApi({
+ resource: 'callflow.get',
+ data: {
+ accountId: self.accountId,
+ callflowId: id
+ },
+ success: function(callflow) {
+ callflow = callflow.data;
+
+ if(typeof(callback) === 'function') {
+ callback(callflow);
+ }
+ },
+ error: function(data) {
+ console.log('Error while getting callflow');
+ console.log(data);
+ }
+ });
+ },
+
+ callflowsExtendMetadataOfCallflowModules: function (callflowsList, callback) {
+ var self = this;
+ var requestsList = {};
+ for (var i = 0, len = callflowsList.length; i< len; i++) {
+ requestsList[callflowsList[i].id] = (function(){
+ var callflowId = callflowsList[i].id;
+ return function (callback) {
+ self.callflowsGetCallflow(callflowId, function (callflow) {
+ callback(null, callflow);
+ })
+ }
+ })();
+ }
+
+ monster.parallel(requestsList, function(error, results) {
+ callback && callback(results);
+ });
+ },
+
renderButtons: function() {
var self = this,
buttons = $(self.getTemplate({
@@ -1107,11 +1183,20 @@ define(function(require) {
$('.buttons').empty();
$('.save', buttons).click(function() {
- if (self.flow.numbers && self.flow.numbers.length > 0) {
- self.save();
- } else {
+ var numbersAndPatternsNotFound = self.flow.numbers.length === 0 && self.flow.patterns.length === 0;
+ var numbersAndPatternsTogether = self.flow.numbers.length > 0 && self.flow.patterns.length > 0;
+
+ if(numbersAndPatternsNotFound) {
monster.ui.alert(self.i18n.active().oldCallflows.invalid_number + '
' + self.i18n.active().oldCallflows.please_select_valid_number);
+ return;
}
+
+ if(numbersAndPatternsTogether) {
+ monster.ui.alert(self.i18n.active().callflows.messages.numbers_and_patterns_together_error);
+ return;
+ }
+
+ self.save();
});
$('.delete', buttons).click(function() {
@@ -1200,6 +1285,7 @@ define(function(require) {
self.flow.root = self.branch('root'); // head of the flow tree
self.flow.root.key = 'flow';
self.flow.numbers = [];
+ self.flow.patterns = [];
self.flow.caption_map = {};
self.formatFlow();
},
@@ -1437,6 +1523,10 @@ define(function(require) {
$.each(flow.numbers, function(key, value) {
s_flow += '|' + value;
});
+ s_flow += '|PATTERNS';
+ $.each(flow.patterns, function(key, value) {
+ s_flow += '|' + value;
+ });
s_flow += '|NODES';
$.each(flow.nodes, function(key, value) {
s_flow += '|' + key + '::';
@@ -1476,7 +1566,7 @@ define(function(require) {
flow.root = self.branch('root');
flow.root.key = 'flow';
- flow.numbers = [];
+ flow.patterns = [];
flow.caption_map = {};
flow.root.index(0);
flow.nodes = flow.root.nodes();
@@ -1492,6 +1582,7 @@ define(function(require) {
flow.nodes = flow.root.nodes();
flow.numbers = callflow.numbers || [];
+ flow.patterns = callflow.patterns || [];
//prepare html from callflow
@@ -1512,16 +1603,23 @@ define(function(require) {
}
}));
- for (var counter, size = flow.numbers.length, j = Math.floor((size) / 2) + 1, i = 0; i < j; i++) {
+ var numbersFormatted = _.map(flow.numbers, function(number) {
+ return _.startsWith('+', number)
+ ? monster.util.formatPhoneNumber(number)
+ : number;
+ });
+ var numbersAndPatterns = numbersFormatted.concat(flow.patterns);
+ for (var counter, size = numbersAndPatterns.length, j = Math.floor((size) / 2) + 1, i = 0; i < j; i++) {
counter = i * 2;
- var numbers = flow.numbers.slice(counter, (counter + 2 < size) ? counter + 2 : size),
- row = $(self.getTemplate({
- name: 'rowNumber',
- data: {
- numbers: numbers
- }
- }));
+ var currentNumbersAndPatterns = numbersAndPatterns.slice(counter, (counter + 2 < size) ? counter + 2 : size);
+
+ var row = $(self.getTemplate({
+ name: 'rowNumber',
+ data: {
+ numbers: currentNumbersAndPatterns
+ }
+ }));
node_html
.find('.content')
@@ -1603,20 +1701,24 @@ define(function(require) {
});
});
- for (var counter, size = self.flow.numbers.length, j = Math.floor((size) / 2) + 1, i = 0; i < j; i++) {
+ var numbersFormatted = _.map(self.flow.numbers, function(number) {
+ return _.startsWith('+', number)
+ ? monster.util.formatPhoneNumber(number)
+ : number;
+ });
+
+ var numbersAndPatterns = numbersFormatted.concat(self.flow.patterns);
+ for (var counter, size = numbersAndPatterns.length, j = Math.floor((size) / 2) + 1, i = 0; i < j; i++) {
counter = i * 2;
- var numbers = self.flow.numbers.slice(counter, (counter + 2 < size) ? counter + 2 : size),
- row = $(self.getTemplate({
- name: 'rowNumber',
- data: {
- numbers: _.map(numbers, function(number) {
- return _.startsWith('+', number)
- ? monster.util.formatPhoneNumber(number)
- : number;
- })
- }
- }));
+ var currentNumbersAndPatterns = numbersAndPatterns.slice(counter, (counter + 2 < size) ? counter + 2 : size);
+
+ var row = $(self.getTemplate({
+ name: 'rowNumber',
+ data: {
+ numbers: currentNumbersAndPatterns
+ }
+ }));
node_html
.find('.content')
@@ -1646,9 +1748,7 @@ define(function(require) {
title: self.i18n.active().oldCallflows.add_number
});
- monster.ui.chosen(popup_html.find('#list_numbers'), {
- width: '160px'
- });
+ monster.ui.chosen(popup_html.find('#list_numbers'), {});
// Have to do that so that the chosen dropdown isn't hidden.
popup_html.parent().css('overflow', 'visible');
@@ -1673,15 +1773,21 @@ define(function(require) {
});
};
- $('.extensions_content', popup).hide();
+ $('.js-add-number-content', popup).hide();
+ $('.js-list-numbers-content', popup).show();
$('input[name="number_type"]', popup).click(function() {
- if ($(this).val() === 'your_numbers') {
- $('.list_numbers_content', popup).show();
- $('.extensions_content', popup).hide();
- } else {
- $('.extensions_content', popup).show();
- $('.list_numbers_content', popup).hide();
+ $('.js-add-number-content', popup).hide();
+ switch($(this).val()) {
+ case 'your_numbers':
+ $('.js-list-numbers-content', popup).show();
+ break;
+ case 'extension':
+ $('.js-extensions-content', popup).show();
+ break;
+ default: // case 'pattern':
+ $('.js-pattern-content', popup).show();
+ break;
}
});
@@ -1714,38 +1820,23 @@ define(function(require) {
$('.add_number', popup).click(function(event) {
event.preventDefault();
- var number = $('input[name="number_type"]:checked', popup).val() === 'your_numbers' ? $('#list_numbers option:selected', popup).val() : $('#add_number_text', popup).val();
-
- if (number !== 'select_none' && number !== '') {
- self.flow.numbers.push(number);
- popup.dialog('close');
-
- self.repaintFlow();
-
- if (self.tour
- && $('#ws_callflow .number_column').not('.js-add-number').length === 1) {
- if (self.tour.ended()) {
- self.tour.restart();
- }
- if (self.tour.getCurrentStep() !== 2) {
- self.tour.goTo(2);
- }
- }
- } else {
- monster.ui.alert(self.i18n.active().oldCallflows.you_didnt_select);
- }
+ self.callflowsAddNumberOrPattern(this, popup);
});
});
});
$('.number_column .delete', node_html).click(function() {
- var number = $(this).parent('.number_column').data('number') + '',
- index = $.inArray(number, self.flow.numbers);
+ var numberOrPattern = $(this).parent('.number_column').data('number') + '';
+ var indexInNumbers = $.inArray(numberOrPattern, self.flow.numbers);
+ var indexInPatterns = $.inArray(numberOrPattern, self.flow.patterns);
- if (index >= 0) {
- self.flow.numbers.splice(index, 1);
+ if(indexInNumbers !== -1) {
+ self.flow.numbers.splice(indexInNumbers, 1);
}
+ if(indexInPatterns !== -1) {
+ self.flow.patterns.splice(indexInPatterns, 1);
+ }
self.repaintFlow();
});
} else {
@@ -1915,14 +2006,87 @@ define(function(require) {
});
$('.node-options .jump', layout).click(function() {
- var $this = $(this),
- callflowId = $this.attr('id');
- self.editCallflow({ id: callflowId });
- });
+ var $this = $(this),
+ callflowId = $this.attr('id');
+ self.editCallflow({ id: callflowId });
+ });
return layout;
},
+ callflowsAddNumberOrPattern: function (button, popup) {
+ var self = this,
+ numberType = $('input[name="number_type"]:checked', popup).val(),
+ pattern = '',
+ number = '',
+ $messageContainer = $('.js-message-container', popup),
+ togetherErrorMessage = self.i18n.active().callflows.messages.numbers_and_patterns_together_error;
+
+ var showNextTourStep = function () {
+ if (self.tour
+ && $('#ws_callflow .number_column').not('.js-add-number').length === 1) {
+ if (self.tour.ended()) {
+ self.tour.restart();
+ }
+ if (self.tour.getCurrentStep() !== 2) {
+ self.tour.goTo(2);
+ }
+ }
+ };
+
+ switch(numberType) {
+ case 'your_numbers':
+ number = $('#list_numbers option:selected', popup).val();
+ break;
+ case 'extension':
+ number = $('#add_number_text', popup).val();
+ break;
+ default: // case 'pattern':
+ pattern = $('#add_pattern_text', popup).val();
+ break;
+ }
+
+ if (number && number === 'select_none') {
+ monster.ui.alert(self.i18n.active().oldCallflows.you_didnt_select);
+ }
+
+ if (number) {
+ if (self.flow.patterns.length > 0) {
+ $messageContainer.empty();
+ self.callflowsInsertAlertMessage($messageContainer, 'warning', togetherErrorMessage);
+ return;
+ }
+ self.flow.numbers.push(number);
+ self.repaintFlow();
+ showNextTourStep();
+ popup.dialog('close');
+ return;
+ }
+
+ if (pattern) {
+ if (self.flow.numbers.length > 0) {
+ $messageContainer.empty();
+ self.callflowsInsertAlertMessage($messageContainer, 'warning', togetherErrorMessage);
+ return;
+ }
+ self.flow.patterns.push(pattern);
+ self.repaintFlow();
+ showNextTourStep();
+ popup.dialog('close');
+ }
+ },
+
+ callflowsInsertAlertMessage: function ($target, type, message, additionalClasses) {
+ var validTypes = ['info', 'question', 'error', 'warning'];
+ type = typeof type === 'string' && validTypes.indexOf(type) >= 0 ? type : 'info';
+ var templateData = {
+ className: additionalClasses ? 'callflows-message ' + additionalClasses : 'callflows-message',
+ content: message
+ };
+ var template = monster.template(monster.apps.core, 'monster-text-' + type, templateData, false, false, true);
+ $target.append(template);
+ },
+
renderBranch: function(branch) {
var self = this,
flow = $(self.getTemplate({
@@ -2133,14 +2297,23 @@ define(function(require) {
},
save: function() {
- var self = this;
+ var self = this,
+ haveNumbers = self.flow.numbers && self.flow.numbers.length > 0,
+ havePatterns = self.flow.patterns && self.flow.patterns.length > 0;
- if (self.flow.numbers && self.flow.numbers.length > 0) {
+ if (haveNumbers || havePatterns) {
var data_request = {
- numbers: self.flow.numbers,
flow: (self.flow.root.children[0] === undefined) ? {} : self.flow.root.children[0].serialize()
};
+ if(haveNumbers) {
+ data_request.numbers = self.flow.numbers;
+ }
+
+ if(havePatterns) {
+ data_request.patterns = self.flow.patterns;
+ }
+
if (self.flow.name !== '') {
data_request.name = self.flow.name;
} else {
diff --git a/src/apps/callflows/i18n/en-US.json b/src/apps/callflows/i18n/en-US.json
index 298f3b7..3591e04 100644
--- a/src/apps/callflows/i18n/en-US.json
+++ b/src/apps/callflows/i18n/en-US.json
@@ -16,6 +16,10 @@
}
},
"callflows": {
+ "messages": {
+ "numbers_and_patterns_together_error": "A callflow should include a list of numbers or regex patterns only"
+ },
+ "pattern": "Pattern",
"addCallflow": "Add Callflow",
"searchDatabase": "Search Database",
"buyNumbers": "Buy Numbers",
@@ -1372,7 +1376,7 @@
"giving_a_name_to_a_callflow": "Giving a name to a callflow isn't mandatory. Leave the field blank and the callflow will be displayed in the left listing as the list of numbers used in this callflow.",
"popup_title": "Edit Callflow Name",
"callflow_preview_title": "Callflow Preview",
- "add_number": "Add number",
+ "add_number": "Add number or pattern",
"add_a_number": "Add a number",
"available_numbers": "Spare Numbers",
"extension": "Extension",
diff --git a/src/apps/callflows/style/app.css b/src/apps/callflows/style/app.css
index 98f00d9..4ba8912 100644
--- a/src/apps/callflows/style/app.css
+++ b/src/apps/callflows/style/app.css
@@ -454,8 +454,10 @@
padding-right: 0px;
}
+#ws_callflow .details a,
.callflow-preview .details a {
- color: #22A5FF;
+ color: white;
+ text-decoration: underline;
}
.callflow-preview * {
@@ -1913,6 +1915,41 @@
background: url('static/images/callflows-drag-and-drop.gif') no-repeat;
}
+.callflows-form.form-inline .form-label-wrapper {
+ display: inline-block;
+ vertical-align: top;
+ text-align: left;
+ width: 160px;
+ margin-right: 0;
+ margin-bottom: 13px;
+ padding-top: 10px;
+}
+
+.callflows-form.form-inline .form-field-wrapper {
+ display: inline-block;
+ vertical-align: top;
+}
+
+.callflows-message-container {
+ padding: 10px 20px 20px;
+}
+
+.callflows-message {
+ border: 1px solid #22A5FF;
+ background: #22A5FF;
+}
+
+.callflows-message .text-wrapper {
+ color: white;
+}
+
+.help-box .wrapper-icon {
+ background: white;
+}
+
+.callflows-message .fa {
+ color: #22A5FF !important;
+}
/*
* Bootstrap guide tour - override styles
diff --git a/src/apps/callflows/submodules/misc/misc.js b/src/apps/callflows/submodules/misc/misc.js
index 72a0e04..102a934 100644
--- a/src/apps/callflows/submodules/misc/misc.js
+++ b/src/apps/callflows/submodules/misc/misc.js
@@ -87,14 +87,19 @@ define(function(require) {
var id = node.getMetadata('id'),
return_value = '';
- if (id in caption_map) {
- if (caption_map[id].hasOwnProperty('name')) {
+ var callflow,
+ numbers,
+ patterns;
+ if (id in caption_map && caption_map.hasOwnProperty(id)) {
+ callflow = caption_map[id];
+ if (callflow.name) {
return_value = caption_map[id].name;
- } else if (caption_map[id].hasOwnProperty('numbers')) {
- return_value = caption_map[id].numbers.toString();
+ } else {
+ numbers = callflow.numbers || [];
+ patterns = callflow.patterns || [];
+ return_value = numbers.concat(patterns).join(', ');
}
}
-
return return_value;
},
edit: function(node, callback) {
@@ -111,8 +116,13 @@ define(function(require) {
$.each(data.data, function() {
if (!this.featurecode && this.id !== self.flow.id) {
- this.name = this.name ? this.name : ((this.numbers) ? this.numbers.toString() : self.i18n.active().oldCallflows.no_numbers);
-
+ if (!this.name) {
+ if(this.numbers && this.numbers.length > 0) {
+ this.name = this.numbers ? this.numbers.join(', ') : self.i18n.active().oldCallflows.no_numbers
+ } else if (this.patterns && this.patterns.length > 0) {
+ this.name = this.patterns ? this.patterns.join(', ') : self.i18n.active().oldCallflows.no_numbers
+ }
+ }
_data.push(this);
}
});
@@ -503,23 +513,23 @@ define(function(require) {
});
}
},
- 'webhook[]': {
- name: self.i18n.active().callflows.webhook.title,
- icon: 'upload',
- category: self.i18n.active().oldCallflows.advanced_cat,
- module: 'webhook',
- tip: self.i18n.active().callflows.webhook.tip,
- data: {},
- rules: [],
- isUsable: 'true',
- weight: 170,
- caption: function() {
- return '';
- },
- edit: function(node, callback) {
- self.miscRenderEditWebhook(node, callback);
- }
- },
+ 'webhook[]': {
+ name: self.i18n.active().callflows.webhook.title,
+ icon: 'upload',
+ category: self.i18n.active().oldCallflows.advanced_cat,
+ module: 'webhook',
+ tip: self.i18n.active().callflows.webhook.tip,
+ data: {},
+ rules: [],
+ isUsable: 'true',
+ weight: 170,
+ caption: function() {
+ return '';
+ },
+ edit: function(node, callback) {
+ self.miscRenderEditWebhook(node, callback);
+ }
+ },
'set_alert_info[]': {
name: self.i18n.active().callflows.setAlertInfo.name,
icon: 'play',
@@ -1258,13 +1268,13 @@ define(function(require) {
}));
if ($('#media_selector option:selected', popup_html).val() === undefined
- || $('#media_selector option:selected', popup_html).val() === 'null') {
+ || $('#media_selector option:selected', popup_html).val() === 'null') {
$('#edit_link', popup_html).hide();
}
$('#media_selector', popup_html).change(function() {
if ($('#media_selector option:selected', popup_html).val() === undefined
- || $('#media_selector option:selected', popup_html).val() === 'null') {
+ || $('#media_selector option:selected', popup_html).val() === 'null') {
$('#edit_link', popup_html).hide();
} else {
$('#edit_link', popup_html).show();
diff --git a/src/apps/callflows/views/addNumber.html b/src/apps/callflows/views/addNumber.html
index a541493..940a662 100644
--- a/src/apps/callflows/views/addNumber.html
+++ b/src/apps/callflows/views/addNumber.html
@@ -1,45 +1,47 @@