define(function(require){ var $ = require('jquery'), _ = require('underscore'), chosen = require('chosen'), monster = require('monster'), timezone = require('monster-timezone'), toastr = require('toastr'); var app = { requests: { /* Users */ 'voip.users.getUsers': { url: 'accounts/{accountId}/users', verb: 'GET' }, 'voip.users.updateUser': { url: 'accounts/{accountId}/users/{userId}', verb: 'POST' }, 'voip.users.createUser': { url: 'accounts/{accountId}/users', verb: 'PUT' }, 'voip.users.getUser': { url: 'accounts/{accountId}/users/{userId}', verb: 'GET' }, 'voip.users.deleteUser': { url: 'accounts/{accountId}/users/{userId}', verb: 'DELETE' }, /* VMBoxes*/ 'voip.users.listVMBoxes': { url: 'accounts/{accountId}/vmboxes', verb: 'GET' }, 'voip.users.createVMBox': { url: 'accounts/{accountId}/vmboxes', verb: 'PUT' }, 'voip.users.getVMBox': { url: 'accounts/{accountId}/vmboxes/{vmboxId}', verb: 'GET' }, 'voip.users.updateVMBox': { url: 'accounts/{accountId}/vmboxes/{vmboxId}', verb: 'POST' }, 'voip.users.deleteVMBox': { url: 'accounts/{accountId}/vmboxes/{vmboxId}', verb: 'DELETE' }, 'voip.users.listUserVMBoxes': { url: 'accounts/{accountId}/vmboxes?filter_owner_id={userId}', verb: 'GET' }, /* Callflows */ 'voip.users.getCallflows': { url: 'accounts/{accountId}/callflows', verb: 'GET' }, 'voip.users.createCallflow': { url: 'accounts/{accountId}/callflows', verb: 'PUT' }, 'voip.users.listUserCallflows': { url: 'accounts/{accountId}/callflows?filter_owner_id={userId}', verb: 'GET' }, 'voip.users.getCallflow': { url: 'accounts/{accountId}/callflows/{callflowId}', verb: 'GET' }, 'voip.users.updateCallflow': { url: 'accounts/{accountId}/callflows/{callflowId}', verb: 'POST' }, 'voip.users.deleteCallflow': { url: 'accounts/{accountId}/callflows/{callflowId}', verb: 'DELETE' }, 'voip.users.listConfNumbers': { url: 'accounts/{accountId}/callflows?filter_type=conference', verb: 'GET' }, /* Devices */ 'voip.users.listDevices': { url: 'accounts/{accountId}/devices', verb: 'GET' }, 'voip.users.listUserDevices': { url: 'accounts/{accountId}/devices?filter_owner_id={userId}', verb: 'GET' }, 'voip.users.getDevice': { url: 'accounts/{accountId}/devices/{deviceId}', verb: 'GET' }, 'voip.users.updateDevice': { url: 'accounts/{accountId}/devices/{deviceId}', verb: 'POST' }, 'voip.users.deleteDevice': { url: 'accounts/{accountId}/devices/{deviceId}', verb: 'DELETE' }, /* Directories */ 'voip.users.listDirectories': { url: 'accounts/{accountId}/directories', verb: 'GET' }, 'voip.users.createDirectory': { url: 'accounts/{accountId}/directories', verb: 'PUT' }, /* Conferences */ 'voip.users.createConference': { url: 'accounts/{accountId}/conferences', verb: 'PUT' }, 'voip.users.getConference': { url: 'accounts/{accountId}/conferences/{conferenceId}', verb: 'GET' }, 'voip.users.updateConference': { url: 'accounts/{accountId}/conferences/{conferenceId}', verb: 'POST' }, 'voip.users.deleteConference': { url: 'accounts/{accountId}/conferences/{conferenceId}', verb: 'DELETE' }, 'voip.users.listUserConferences': { url: 'accounts/{accountId}/conferences?filter_owner_id={userId}', verb: 'GET' }, /* Media */ 'voip.users.listMedia': { url: 'accounts/{accountId}/media?key_missing=type', verb: 'GET' }, 'voip.users.createMedia': { url: 'accounts/{accountId}/media', verb: 'PUT' }, 'voip.users.deleteMedia': { url: 'accounts/{accountId}/media/{mediaId}', verb: 'DELETE' }, 'voip.users.uploadMedia': { url: 'accounts/{accountId}/media/{mediaId}/raw', verb: 'POST', type: 'application/x-base64' }, /* Misc */ 'voip.users.getNumbers': { url: 'accounts/{accountId}/phone_numbers', verb: 'GET' }, 'voip.users.resendInstructions': { apiRoot: 'apps/voip/submodules/users/fixtures/', url: 'resendInstructions.json', verb: 'POST' }, 'voip.users.resetPassword': { apiRoot: 'apps/voip/submodules/users/fixtures/', url: 'resetPassword.json', verb: 'POST' } /*, 'voip.users.resendInstructions': { url: 'accounts/{accountId}/users/{userId}/resend_instructions', verb: 'POST' }, 'voip.users.resetPassword': { url: 'accounts/{accountId}/users/{userId}/reset_password', verb: 'POST' }, */ }, subscribe: { 'voip.users.render': 'usersRender' }, /* Users */ /* args: parent and userId */ usersRender: function(args) { var self = this, args = args || {}, parent = args.parent || $('.right-content'), _userId = args.userId, _openedTab = args.openedTab; self.usersRemoveOverlay(); self.usersGetData(function(data) { var dataTemplate = self.usersFormatListData(data), template = $(monster.template(self, 'users-layout', dataTemplate)), templateUser; _.each(dataTemplate.users, function(user) { templateUser = monster.template(self, 'users-row', user); template.find('.user-rows').append(templateUser); }); self.usersBindEvents(template, parent, dataTemplate); parent .empty() .append(template); if(_userId) { var cells = parent.find('.grid-row[data-id=' + _userId + '] .grid-cell'); monster.ui.fade(cells); } if ( dataTemplate.users.length == 0) { parent.find('.grid-row.title').css('display', 'none'); parent.find('.no-users-row').css('display', 'block'); } else { parent.find('.grid-row.title').css('display', 'block'); parent.find('.no-users-row').css('display', 'none'); } if(_userId && _openedTab) { template.find('.grid-row[data-id="'+ _userId +'"] .grid-cell[data-type="' + _openedTab + '"]').click(); args.callback && args.callback(); } }); }, usersFormatUserData: function(dataUser, _mainDirectory, _mainCallflow, _vmbox, _vmboxes) { var self = this, formattedUser = { additionalDevices: 0, additionalExtensions: 0, additionalNumbers: 0, devices: [], extension: '', hasFeatures: false, isAdmin: dataUser.priv_level === 'admin', listCallerId: [], listExtensions: [], listNumbers: [], phoneNumber: '', differentEmail: dataUser.email !== dataUser.username, mapFeatures: { caller_id: { icon: 'icon-user', iconColor: 'icon-blue', title: self.i18n.active().users.caller_id.title }, call_forward: { icon: 'icon-mail-forward', iconColor: 'icon-yellow', title: self.i18n.active().users.call_forward.title }, hotdesk: { icon: 'icon-fire', iconColor: 'icon-orange', title: self.i18n.active().users.hotdesk.title }, vm_to_email: { icon: 'icon-telicon-voicemail', iconColor: 'icon-green', title: self.i18n.active().users.vm_to_email.title }, faxing: { icon: 'icon-telicon-fax', iconColor: 'icon-red', title: self.i18n.active().users.faxing.title }, conferencing: { icon: 'icon-comments', iconColor: 'icon-gray', title: self.i18n.active().users.conferencing.title }, find_me_follow_me: { icon: 'icon-sitemap', iconColor: 'icon-purple', title: self.i18n.active().users.find_me_follow_me.title }, music_on_hold: { icon: 'icon-music', iconColor: 'icon-pink', title: self.i18n.active().users.music_on_hold.title }, call_recording: { icon: 'icon-microphone', iconColor: 'icon-blue', title: self.i18n.active().users.callRecording.title } } }; if(!('extra' in dataUser)) { dataUser.extra = formattedUser; } // console.log(_mainCallflow) dataUser.extra.countFeatures = 0; _.each(dataUser.features, function(v) { if(v in dataUser.extra.mapFeatures) { dataUser.extra.countFeatures++; dataUser.extra.mapFeatures[v].active = true; } }); if(dataUser.extra.countFeatures > 0) { dataUser.extra.hasFeatures = true; } if(_mainDirectory) { dataUser.extra.mainDirectoryId = _mainDirectory.id; if('directories' in dataUser && _mainDirectory.id in dataUser.directories) { dataUser.extra.includeInDirectory = true; } else { dataUser.extra.includeInDirectory = false; } } if(_mainCallflow) { dataUser.extra.mainCallflowId = _mainCallflow.id; if('flow' in _mainCallflow) { var flow = _mainCallflow.flow, module = 'user'; if(dataUser.features.indexOf('find_me_follow_me') >= 0) { module = 'ring_group'; dataUser.extra.groupTimeout = true; } while(flow.module != module && '_' in flow.children) { flow = flow.children['_']; } dataUser.extra.ringingTimeout = flow.data.timeout; } } if(_vmbox) { dataUser.extra.vmbox = _vmbox; } if(!_.isEmpty(_vmbox) && !_.isEmpty(_vmboxes)) { var i = _vmboxes.indexOf(_vmbox.mailbox); _vmboxes.splice(i, 1); dataUser.extra.existingVmboxes = _vmboxes; } dataUser.extra.adminId = self.userId; return dataUser; }, usersFormatListData: function(data) { var self = this, dataTemplate = { existingExtensions: [], countUsers: data.users.length }, mapUsers = {}; _.each(data.users, function(user) { mapUsers[user.id] = self.usersFormatUserData(user); }); _.each(data.callflows, function(callflow) { if(callflow.type !== 'faxing') { var userId = callflow.owner_id; _.each(callflow.numbers, function(number) { if(number && number.length < 7) { dataTemplate.existingExtensions.push(number); } }); if(userId in mapUsers) { var user = mapUsers[userId]; //User can only have one phoneNumber and one extension displayed with this code _.each(callflow.numbers, function(number) { if(number.length < 7) { user.extra.listExtensions.push(number); if(user.extra.extension === '') { user.extra.extension = number; } else { user.extra.additionalExtensions++; } } else { user.extra.listCallerId.push(number); user.extra.listNumbers.push(number); if(user.extra.phoneNumber === '') { user.extra.phoneNumber = number; } else { user.extra.additionalNumbers++; } } }); } } }); dataTemplate.existingExtensions.sort(self.usersSortExtensions); _.each(data.devices, function(device) { var userId = device.owner_id; if(userId in mapUsers) { if(mapUsers[userId].extra.devices.length == 2) { mapUsers[userId].extra.additionalDevices++; } else { mapUsers[userId].extra.devices.push(device.device_type); } } }); var sortedUsers = []; _.each(mapUsers, function(user) { sortedUsers.push(user); }); sortedUsers = monster.util.sort(sortedUsers, 'last_name'); dataTemplate.users = sortedUsers; return dataTemplate; }, usersBindEvents: function(template, parent, data) { var self = this, currentNumberSearch = '', currentUser, currentCallflow, existingExtensions = data.existingExtensions, extensionsToSave, numbersToSave, toastrMessages = self.i18n.active().users.toastrMessages, mainDirectoryId, mainCallflowId, listUsers = data, renderFindMeFollowMeFeature = function(featureCallback) { monster.parallel({ userDevices: function(callback) { monster.request({ resource: 'voip.users.listUserDevices', data: { accountId: self.accountId, userId: currentUser.id }, success: function(data) { callback(null, data.data); } }); }, userCallflow: function(callback) { self.usersListCallflowsUser(currentUser.id, function(data) { if(data.length > 0) { monster.request({ resource: 'voip.users.getCallflow', data: { accountId: self.accountId, callflowId: data[0].id }, success: function(callflow) { callback(null, callflow.data) } }); } else { callback(null, null); } }); } }, function(error, results) { self.usersRenderFindMeFollowMe($.extend(true, results, { currentUser: currentUser, saveCallback: featureCallback })); } ); }; template.find('.grid-row:not(.title) .grid-cell').on('click', function() { var cell = $(this), type = cell.data('type'), row = cell.parents('.grid-row'), userId = row.data('id'); template.find('.edit-user').slideUp("400", function() { $(this).empty(); }); if(cell.hasClass('active')) { template.find('.grid-cell').removeClass('active'); template.find('.grid-row').removeClass('active'); self.usersRemoveOverlay(); cell.css({ 'position': 'inline-block', 'z-index': '0' }); cell.parent().siblings('.edit-user').css({ 'position': 'block', 'z-index': '0' }); } else { template.find('.grid-cell').removeClass('active'); template.find('.grid-row').removeClass('active'); cell.toggleClass('active'); row.toggleClass('active'); cell.css({ 'position': 'relative', 'z-index': '3' }); cell.parent().siblings('.edit-user').css({ 'position': 'relative', 'z-index': '2' }); self.usersGetTemplate(type, userId, listUsers, function(template, data) { if(type === 'name') { currentUser = data; template.find('#user_timezone').chosen({search_contains: true, width: "61%"}); data.extra.differentEmail ? template.find('.email-group').show() : template.find('.email-group').hide(); if(data.extra.mainDirectoryId) { mainDirectoryId = data.extra.mainDirectoryId; } if(data.extra.mainCallflowId) { mainCallflowId = data.extra.mainCallflowId; } } else if(type === 'numbers') { extensionsToSave = []; currentCallflow = data.callflow; _.each(data.extensions, function(number) { extensionsToSave.push(number); }); } else if(type === 'extensions') { existingExtensions = data.allExtensions; currentCallflow = data.callflow; numbersToSave = []; _.each(data.assignedNumbers, function(v, k) { numbersToSave.push(k); }); } else if(type === 'features') { currentUser = data; } //FancyCheckboxes. monster.ui.prettyCheck.create(template); row.find('.edit-user').append(template).slideDown(); $('body').append($('
')); }); } }); template.find('.users-header .search-query').on('keyup', function() { var searchString = $(this).val().toLowerCase(), rows = template.find('.user-rows .grid-row:not(.title)'), emptySearch = template.find('.user-rows .empty-search-row'); _.each(rows, function(row) { var row = $(row); row.data('search').toLowerCase().indexOf(searchString) < 0 ? row.hide() : row.show(); }); if(rows.size() > 0) { rows.is(':visible') ? emptySearch.hide() : emptySearch.show(); } }); template.find('.users-header .add-user').on('click', function() { monster.parallel({ callflows: function(callback) { self.usersListCallflows(function(callflows) { callback(null, callflows); }); }, vmboxes: function(callback) { self.usersListVMBoxes(function(vmboxes) { callback(null, vmboxes); }); } }, function(err, results) { var originalData = self.usersFormatAddUser(results), userTemplate = $(monster.template(self, 'users-creation', originalData)); timezone.populateDropdown(userTemplate.find('#user_creation_timezone')); monster.ui.prettyCheck.create(userTemplate); monster.ui.validate(userTemplate.find('#form_user_creation'), { rules: { 'callflow.extension': { checkList: originalData.listExtensions }, 'vmbox.number': { checkList: originalData.listVMBoxes } }, messages: { 'user.first_name': { required: self.i18n.active().validation.required }, 'user.last_name': { required: self.i18n.active().validation.required }, 'callflow.extension': { required: self.i18n.active().validation.required } } }); userTemplate.find('#create_user').on('click', function() { if(monster.ui.valid(userTemplate.find('#form_user_creation'))) { var dataForm = form2object('form_user_creation'), formattedData = self.usersFormatCreationData(dataForm); self.usersCreate(formattedData, function(data) { popup.dialog('close').remove(); self.usersRender({ userId: data.user.id }); }); } }); userTemplate.find('#notification_email').on('ifChanged', function() { userTemplate.find('.email-group').toggleClass('hidden'); }); var popup = monster.ui.dialog(userTemplate, { title: self.i18n.active().users.dialogCreationUser.title }); } ); }); template.on('click', '.cancel-link', function() { template.find('.edit-user').slideUp("400", function() { $(this).empty(); template.find('.grid-cell.active').css({ 'position': 'inline-block', 'z-index': '0' }); template.find('.grid-row.active .edit-user').css({ 'position': 'block', 'z-index': '0' }); template.find('.grid-row.active').removeClass('active'); self.usersRemoveOverlay(); template.find('.grid-cell.active').removeClass('active'); }); }); /* Events for Extensions details */ template.on('click', '.save-extensions', function() { var $this = $(this), numbers = $.extend(true, [], numbersToSave), name = $this.parents('.grid-row').find('.grid-cell.name').text(), userId = $this.parents('.grid-row').data('id'); template.find('.extensions .list-assigned-items .item-row').each(function(k, row) { var row = $(row), number; number = (row.data('id') ? row.data('id') : row.find('.input-extension').val()) + ''; numbers.push(number); }); self.usersUpdateCallflowNumbers(userId, (currentCallflow || {}).id, numbers, function(callflowData) { toastr.success(monster.template(self, '!' + toastrMessages.numbersUpdated, { name: name })); self.usersRender({ userId: callflowData.owner_id }); }); }); template.on('click', '#add_extensions', function() { var nextExtension = parseInt(self.usersGetNextInt(existingExtensions)) + '', dataTemplate = { recommendedExtension: nextExtension }, newLineTemplate = $(monster.template(self, 'users-newExtension', dataTemplate)), listExtensions = template.find('.extensions .list-assigned-items'); listExtensions.find('.empty-row').hide(); listExtensions.append(newLineTemplate); existingExtensions.push(nextExtension); }); template.on('click', '.remove-extension', function() { var phoneRow = $(this).parents('.item-row'), emptyRow = phoneRow.siblings('.empty-row'); if(phoneRow.siblings('.item-row').size() === 0) { emptyRow.show(); } phoneRow.remove(); }); template.on('click', '.cancel-extension-link', function() { var extension = $(this).siblings('input').val(), index = existingExtensions.indexOf(extension); if(index > -1) { existingExtensions.splice(index, 1); } $(this).parents('.item-row').remove(); }); /* Events for Users detail */ template.on('click', '#resend_instructions', function() { var userId = $(this).parents('.grid-row').data('id'); monster.request({ resource: 'voip.users.resendInstructions', data: { accountId: self.accountId, userId: userId }, success: function(data) { toastr.success(monster.template(self, '!' + toastrMessages.instructionsSent, { email: currentUser.email })); } }); }); template.on('click', '#reset_password', function() { var userId = $(this).parents('.grid-row').data('id'); monster.request({ resource: 'voip.users.resetPassword', data: { accountId: self.accountId, userId: userId }, success: function(data) { toastr.success(monster.template(self, '!' + toastrMessages.passwordReseted, { email: currentUser.email })); } }); }); template.on('click', '#delete_user', function() { var dataUser = $(this).parents('.grid-row').data(), deleteType = dataUser.priv_level === 'admin' ? 'confirmDeleteAdmin' : 'confirmDeleteUser'; monster.ui.confirm(self.i18n.active().users[deleteType], function() { self.usersDelete(dataUser.id, function(data) { toastr.success(monster.template(self, '!' + toastrMessages.userDeleted)); }); }); }); template.on('ifChanged', '#notification_email', function() { if ( template.find('.email-border').hasClass('open') ) { template.find('.email-border').removeClass('open', 400); template.find('.email-group').slideUp(); } else { template.find('.email-group').slideDown(); template.find('.email-border').addClass('open', 400); } }); template.on('click', '.save-user', function() { var formData = form2object('form-'+currentUser.id), form = template.find('#form-'+currentUser.id); monster.util.checkVersion(currentUser, function() { if(monster.ui.valid(form)) { currentUser.extra.vmbox.mailbox = formData.extra.vmboxNumber; currentUser.extra.vmbox.timezone = formData.timezone; var userToSave = $.extend(true, {}, currentUser, formData); monster.parallel({ vmbox: function(callback) { self.usersSmartUpdateVMBox(userToSave, true, function(vmbox) { callback(null, vmbox); }); }, user: function(callback) { self.usersUpdateUser(userToSave, function(userData) { callback(null, userData.data); }); }, callflow: function(callback) { if(userToSave.extra.ringingTimeout && userToSave.features.indexOf('find_me_follow_me') < 0) { self.usersGetMainCallflow(userToSave.id, function(mainCallflow) { if('flow' in mainCallflow) { var flow = mainCallflow.flow; while(flow.module != 'user' && '_' in flow.children) { flow = flow.children['_']; } flow.data.timeout = parseInt(userToSave.extra.ringingTimeout); self.usersUpdateCallflow(mainCallflow, function(updatedCallflow) { callback(null, updatedCallflow); }); } else { callback(null, null); } }); } else { callback(null, null); } } }, function(error, results) { toastr.success(monster.template(self, '!' + toastrMessages.userUpdated, { name: results.user.first_name + ' ' + results.user.last_name })); self.usersRender({ userId: results.user.id }); } ); } }); }); template.on('click', '#change_pin', function() { var pinTemplate = $(monster.template(self, 'users-changePin')), form = pinTemplate.find('#form_new_pin'); //monster.ui.validate(form); monster.ui.validate(form, { rules: { 'pin': { number: true, minlength:4, min: 0 } } }); pinTemplate.find('.save-new-pin').on('click', function() { var formData = form2object('form_new_pin'), vmboxData = $.extend(true, currentUser.extra.vmbox, formData); if(monster.ui.valid(form)) { self.usersUpdateVMBox(vmboxData, function(data) { popup.dialog('close').remove(); toastr.success(monster.template(self, '!' + toastrMessages.pinUpdated, { name: currentUser.first_name + ' ' + currentUser.last_name })); }); } }); pinTemplate.find('.cancel-link').on('click', function() { popup.dialog('close').remove(); }); var popup = monster.ui.dialog(pinTemplate, { title: self.i18n.active().users.dialogChangePin.title }); }); template.on('click', '#change_username', function() { var passwordTemplate = $(monster.template(self, 'users-changePassword', currentUser)), form = passwordTemplate.find('#form_new_username'); passwordTemplate.find('.save-new-username').on('click', function() { var formData = form2object('form_new_username'), userToSave = $.extend(true, {}, currentUser, formData); if(monster.ui.valid(form)) { if(!currentUser.extra.differentEmail) { userToSave.email = userToSave.username; } self.usersUpdateUser(userToSave, function(userData) { currentUser.username = userData.data.username; template.find('#username').html(userData.data.username); if(!currentUser.extra.differentEmail) { template.find('#email').val(userData.data.email); currentUser.email = userData.username; } popup.dialog('close').remove(); toastr.success(monster.template(self, '!' + toastrMessages.userUpdated, { name: userData.data.first_name + ' ' + userData.data.last_name })); }); } }); passwordTemplate.find('.cancel-link').on('click', function() { popup.dialog('close').remove(); }); var popup = monster.ui.dialog(passwordTemplate, { title: self.i18n.active().users.dialogChangePassword.title }); }); template.on('click', '#open_fmfm_link', function() { renderFindMeFollowMeFeature(function(usersRenderArgs) { usersRenderArgs.openedTab = 'name'; self.usersRender(usersRenderArgs); }); }); template.on('focus', '.ringing-timeout.disabled #ringing_timeout', function() { $(this).blur(); }); /* Events for Devices in Users */ template.on('click', '.create-device', function() { var $this = $(this), type = $this.data('type'), userId = $this.parents('.grid-row').data('id'); monster.pub('voip.devices.renderAdd', { type: type, callback: function(device) { var rowDevice = monster.template(self, 'users-rowSpareDevice', device), listAssigned = template.find('.list-assigned-items'); listAssigned.find('.empty-row').hide(); /* reset search */ listAssigned.find('.empty-search-row').hide(); template.find('.unassigned-list-header .search-query').val(''); listAssigned.find('.item-row').show(); /* Add row */ listAssigned.append(rowDevice) .find('.item-row[data-id="' + device.id + '"]') .toggleClass('updated') .find('button') .removeClass('add-device btn-primary') .addClass('remove-device btn-danger') .text(self.i18n.active().remove); } }); }); template.on('click', '.save-devices', function() { var dataDevices = { new: [], old: [] }, name = $(this).parents('.grid-row').find('.grid-cell.name').text(), userId = $(this).parents('.grid-row').data('id'); template.find('.detail-devices .list-assigned-items .item-row.updated').each(function(k, row) { dataDevices.new.push($(row).data('id')); }); template.find('.detail-devices .list-unassigned-items .item-row.updated').each(function(k, row) { dataDevices.old.push($(row).data('id')); }); self.usersUpdateDevices(dataDevices, userId, function() { toastr.success(monster.template(self, '!' + toastrMessages.devicesUpdated, { name: name })); self.usersRender({ userId: userId }); }); }); template.on('click', '.detail-devices .list-unassigned-items .add-device', function() { var row = $(this).parents('.item-row'), spare = template.find('.count-spare'), countSpare = spare.data('count') - 1, assignedList = template.find('.detail-devices .list-assigned-items'); spare .html(countSpare) .data('count', countSpare); row.toggleClass('updated') .find('button') .removeClass('add-device btn-primary') .addClass('remove-device btn-danger') .text(self.i18n.active().remove); assignedList.find('.empty-row').hide(); assignedList.append(row); var rows = template.find('.list-unassigned-items .item-row'); if(rows.size() === 0) { template.find('.detail-devices .list-unassigned-items .empty-row').show(); } else if(rows.is(':visible') === false) { template.find('.detail-devices .list-unassigned-items .empty-search-row').show(); } }); template.on('click', '.detail-devices .list-assigned-items .remove-device', function() { var row = $(this).parents('.item-row'), spare = template.find('.count-spare'), countSpare = spare.data('count') + 1, unassignedList = template.find('.detail-devices .list-unassigned-items'); /* Alter the html */ row.hide(); row.toggleClass('updated') .find('button') .removeClass('remove-device btn-danger') .addClass('add-device btn-primary') .text(self.i18n.active().add); unassignedList.append(row); unassignedList.find('.empty-row').hide(); spare .html(countSpare) .data('count', countSpare); var rows = template.find('.detail-devices .list-assigned-items .item-row'); /* If no rows beside the clicked one, display empty row */ if(rows.is(':visible') === false) { template.find('.detail-devices .list-assigned-items .empty-row').show(); } /* If it matches the search string, show it */ if(row.data('search').indexOf(currentNumberSearch) >= 0) { row.show(); unassignedList.find('.empty-search-row').hide(); } }); /* Events for Numbers in Users */ template.on('click', '.detail-numbers .list-assigned-items .remove-number', function() { var $this = $(this), userName = $this.parents('.grid-row').find('.grid-cell.name').text(), dataNumbers = $.extend(true, [], extensionsToSave), userId = $this.parents('.grid-row').data('id'), row = $this.parents('.item-row'); row.slideUp(function() { row.remove(); if ( !template.find('.list-assigned-items .item-row').is(':visible') ) { template.find('.list-assigned-items .empty-row').slideDown(); } template.find('.item-row').each(function(idx, elem) { dataNumbers.push($(elem).data('id')); }); self.usersUpdateCallflowNumbers(userId, (currentCallflow || {}).id, dataNumbers, function(callflowData) { toastr.success(monster.template(self, '!' + toastrMessages.numbersUpdated, { name: userName })); self.usersRender({ userId: callflowData.owner_id }); }); }); }); template.on('click', '.callerId-number', function() { var cnamCell = $(this).parents('.item-row').first(), phoneNumber = cnamCell.data('id'); if(phoneNumber) { var args = { phoneNumber: phoneNumber, callbacks: { success: function(data) { if('cnam' in data.data && data.data.cnam.display_name) { cnamCell.find('.features i.feature-outbound_cnam').addClass('active'); } else { cnamCell.find('.features i.feature-outbound_cnam').removeClass('active'); } if('cnam' in data.data && data.data.cnam.inbound_lookup) { cnamCell.find('.features i.feature-inbound_cnam').addClass('active'); } else { cnamCell.find('.features i.feature-inbound_cnam').removeClass('active'); } } } }; monster.pub('common.callerId.renderPopup', args); } }); template.on('click', '.e911-number', function() { var e911Cell = $(this).parents('.item-row').first(), phoneNumber = e911Cell.data('id'); if(phoneNumber) { var args = { phoneNumber: phoneNumber, callbacks: { success: function(data) { if(!($.isEmptyObject(data.data.dash_e911))) { e911Cell.find('.features i.feature-dash_e911').addClass('active'); } else { e911Cell.find('.features i.feature-dash_e911').removeClass('active'); } } } }; monster.pub('common.e911.renderPopup', args); } }); template.on('click', '.feature[data-feature="caller_id"]', function() { self.usersRenderCallerId(currentUser); }); template.on('click', '.feature[data-feature="call_forward"]', function() { self.usersRenderCallForward(currentUser); }); template.on('click', '.feature[data-feature="hotdesk"]', function() { self.usersRenderHotdesk(currentUser); }); template.on('click', '.feature[data-feature="find_me_follow_me"]', function() { renderFindMeFollowMeFeature(); }); template.on('click', '.feature[data-feature="call_recording"]', function() { self.usersListCallflowsUser(currentUser.id, function(data) { if(data.length > 0) { monster.request({ resource: 'voip.users.getCallflow', data: { accountId: self.accountId, callflowId: data[0].id }, success: function(callflow) { self.usersRenderCallRecording({ userCallflow: callflow.data, currentUser: currentUser }); } }); } else { monster.ui.alert('error', self.i18n.active().users.call_recording.noNumber); } }); }); template.on('click', '.feature[data-feature="music_on_hold"]', function() { self.usersRenderMusicOnHold(currentUser); }); template.on('click', '.feature[data-feature="vm_to_email"]', function() { self.usersListVMBoxesUser(currentUser.id, function(vmboxes) { currentUser.extra.deleteAfterNotify = true; if(vmboxes.length > 0) { self.usersGetVMBox(vmboxes[0].id, function(data) { currentUser.extra.deleteAfterNotify = data.delete_after_notify; self.usersRenderVMToEmail(currentUser); }); } else { self.usersRenderVMToEmail(currentUser); } }); }); template.on('click', '.feature[data-feature="conferencing"]', function() { self.usersGetConferenceFeature(currentUser.id, function(dataConf) { var data = { listConferences: dataConf.listConfNumbers, user: currentUser, conference: dataConf.conference }; if(_.isEmpty(data.listConferences)) { monster.ui.alert('error', self.i18n.active().users.conferencing.noConfNumbers); } else { self.usersRenderConferencing(data); } }); }); template.on('click', '.feature[data-feature="faxing"]', function() { monster.parallel({ numbers: function(callback) { self.usersListNumbers(function(listNumbers) { var spareNumbers = {}; _.each(listNumbers.numbers, function(number, key) { if(number.used_by === '') { spareNumbers[key] = number; } }); callback && callback(null, spareNumbers); }); }, callflows: function(callback) { self.usersListCallflowsUser(currentUser.id, function(callflows) { var existingCallflow; _.each(callflows, function(callflow) { if(callflow.type === 'faxing') { existingCallflow = callflow; return false; } }); callback && callback(null, existingCallflow) }); } }, function(err, results) { results.user = currentUser; self.usersRenderFaxing(results); } ); }); template.on('click', '.actions .spare-link:not(.disabled)', function(e) { e.preventDefault(); var $this = $(this), args = { accountName: monster.apps['auth'].currentAccount.name, accountId: self.accountId, callback: function(numberList) { var name = $this.parents('.grid-row').find('.grid-cell.name').text(), dataNumbers = $.extend(true, [], extensionsToSave), userId = $this.parents('.grid-row').data('id'); template.find('.empty-row').hide(); template.find('.item-row').each(function(idx, elem) { dataNumbers.push($(elem).data('id')); }); _.each(numberList, function(val, idx) { dataNumbers.push(val.phoneNumber); template .find('.list-assigned-items') .append($(monster.template(self, 'users-numbersItemRow', { number: val }))); }); self.usersUpdateCallflowNumbers(userId, (currentCallflow || {}).id, dataNumbers, function(callflowData) { toastr.success(monster.template(self, '!' + toastrMessages.numbersUpdated, { name: name })); self.usersRender({ userId: callflowData.owner_id }); }); } } monster.pub('common.numbers.dialogSpare', args); }); template.on('click', '.actions .buy-link', function(e) { e.preventDefault(); monster.pub('common.buyNumbers', { searchType: $(this).data('type'), callbacks: { success: function(numbers) { var countNew = 0; monster.pub('common.numbers.getListFeatures', function(features) { _.each(numbers, function(number, k) { countNew++; /* Formating number */ number.viewFeatures = $.extend(true, {}, features); var rowTemplate = monster.template(self, 'users-rowSpareNumber', number); template.find('.list-unassigned-items .empty-row').hide(); template.find('.list-unassigned-items').append(rowTemplate); }); var previous = parseInt(template.find('.unassigned-list-header .count-spare').data('count')), newTotal = previous + countNew; template.find('.unassigned-list-header .count-spare') .data('count', newTotal) .html(newTotal); template.find('.spare-link.disabled').removeClass('disabled'); }); }, error: function(error) { } } }); }); $('body').on('click', '#users_container_overlay', function() { template.find('.edit-user').slideUp("400", function() { $(this).empty(); }); self.usersRemoveOverlay(); template.find('.grid-cell.active').css({ 'position': 'inline-block', 'z-index': '0' }); template.find('.grid-row.active').parent().siblings('.edit-user').css({ 'position': 'block', 'z-index': '0' }); template.find('.grid-cell.active').removeClass('active'); template.find('.grid-row.active').removeClass('active'); }); }, /* Helper function that takes an array of number in parameter, sorts it, and returns the first number not in the array, greater than the minVal */ usersGetNextInt: function(arr) { var orderedArr = arr, prevVal = 0, minVal = 2000, increment = 1; orderedArr.sort(function(a,b) { var parsedA = parseInt(a), parsedB = parseInt(b); return parsedA > parsedB ? 1 : -1; }); _.each(orderedArr, function(val) { var curr = parseInt(val); /* If we already stored a previous value */ if(prevVal) { if(curr - prevVal !== increment) { return prevVal + increment; } } /* Otherwise, if we didn't, and the current value is greater than the minVal, we return the minVal */ else if(curr > minVal) { return minVal; } /* We don't want to return value lower than our min val, so we only store prevVal that are greater than the minVal */ if(curr >= minVal) { prevVal = curr; } }); return (prevVal) ? prevVal + increment : minVal; }, usersFormatAddUser: function(data) { var self = this, formattedData = { sendToSameEmail: true, nextExtension: '', nextVMBox: '', listExtensions: {}, listVMBoxes:{}, }, arrayExtensions = [], arrayVMBoxes = []; _.each(data.callflows, function(callflow) { _.each(callflow.numbers, function(number) { if(number.length < 7) { formattedData.listExtensions[number] = callflow; arrayExtensions.push(number); } }); }); formattedData.nextExtension = parseInt(self.usersGetNextInt(arrayExtensions)) + ''; _.each(data.vmboxes, function(vmbox) { formattedData.listVMBoxes[vmbox.mailbox] = vmbox; arrayVMBoxes.push(vmbox.mailbox); }); //Set the VMBox Number to 2001 if there are no VMBox in the system, or to the latest vmbox number + 1 if there are formattedData.nextVMBox = parseInt(self.usersGetNextInt(arrayVMBoxes)) + ''; return formattedData; }, usersFormatFaxingData: function(data) { var listNumbers = []; if(data.callflows) { if(data.callflows.numbers.length > 0) { listNumbers.push(data.callflows.numbers[0]); } } _.each(data.numbers, function(value, number) { listNumbers.push(number); }); data.extra = $.extend(true, {}, data.extra, { listNumbers: listNumbers }); return data; }, usersRenderConferencing: function(data) { var self = this, data = self.usersFormatConferencingData(data), featureTemplate = $(monster.template(self, 'users-feature-conferencing', data)), switchFeature = featureTemplate.find('.switch').bootstrapSwitch(), featureForm = featureTemplate.find('#conferencing_form'); monster.ui.validate(featureForm); featureTemplate.find('.cancel-link').on('click', function() { popup.dialog('close').remove(); }); switchFeature.on('switch-change', function(e, data) { data.value ? featureTemplate.find('.content').slideDown() : featureTemplate.find('.content').slideUp(); }); featureTemplate.find('.save').on('click', function() { var args = { openedTab: 'features', callback: function() { popup.dialog('close').remove(); } }; if(monster.ui.valid(featureForm)) { data.conference = form2object('conferencing_form'); if(switchFeature.bootstrapSwitch('status')) { self.usersUpdateConferencing(data, function(data) { args.userId = data.user.id; self.usersRender(args); }); } else { self.usersDeleteConferencing(data.user.id, function(data) { args.userId = data.user.data.id; self.usersRender(args); }); } } }); monster.ui.prettyCheck.create(featureTemplate.find('.content')); var popup = monster.ui.dialog(featureTemplate, { title: data.user.extra.mapFeatures.conferencing.title, position: ['center', 20] }); }, usersFormatConferencingData: function(data) { return data; }, usersRenderFaxing: function(data) { var self = this, data = self.usersFormatFaxingData(data), featureTemplate = $(monster.template(self, 'users-feature-faxing', data)), switchFeature = featureTemplate.find('.switch').bootstrapSwitch(); featureTemplate.find('.cancel-link').on('click', function() { popup.dialog('close').remove(); }); switchFeature.on('switch-change', function(e, data) { data.value ? featureTemplate.find('.content').slideDown() : featureTemplate.find('.content').slideUp(); }); featureTemplate.find('.save').on('click', function() { var newNumber = popup.find('.dropdown-numbers').val(), args = { openedTab: 'features', callback: function() { popup.dialog('close').remove(); } }; if(switchFeature.bootstrapSwitch('status')) { self.usersUpdateFaxing(data, newNumber, function(results) { args.userId = results.callflow.owner_id; self.usersRender(args); }); } else { self.usersDeleteFaxing(data.callflows.owner_id, function() { args.userId = data.callflows.owner_id; self.usersRender(args); }); } }); monster.ui.prettyCheck.create(featureTemplate.find('.content')); if(data.extra.listNumbers.length > 0) { var popup = monster.ui.dialog(featureTemplate, { title: data.user.extra.mapFeatures.faxing.title, position: ['center', 20] }); } else { monster.ui.alert('error', self.i18n.active().users.errorNumberFaxing); } }, usersRenderHotdesk: function(currentUser) { var self = this, featureTemplate = $(monster.template(self, 'users-feature-hotdesk', currentUser)), switchFeature = featureTemplate.find('.switch').bootstrapSwitch(), requirePin = featureTemplate.find('[name="require_pin"]'), featureForm = featureTemplate.find('#hotdesk_form'); monster.ui.validate(featureForm); featureTemplate.find('.cancel-link').on('click', function() { popup.dialog('close').remove(); }); switchFeature.on('switch-change', function(e, data) { data.value ? featureTemplate.find('.content').slideDown() : featureTemplate.find('.content').slideUp(); }); requirePin.on('ifChanged', function() { if(requirePin.is(':checked')) { featureTemplate.find('#pin') .removeAttr('disabled', 'disabled') .focus(); } else { featureTemplate.find('#pin') .val('') .attr('disabled', 'disabled'); } }); featureTemplate.find('.save').on('click', function() { if(monster.ui.valid(featureForm)) { var formData = form2object('hotdesk_form'), args = { openedTab: 'features', callback: function() { popup.dialog('close').remove(); } }; formData.enabled = switchFeature.bootstrapSwitch('status'); if(formData.require_pin === false) { delete formData.pin; } delete currentUser.hotdesk; userToSave = $.extend(true, {}, currentUser, { hotdesk: formData }); self.usersUpdateUser(userToSave, function(data) { args.userId = data.data.id; self.usersRender(args); }); } }); monster.ui.prettyCheck.create(featureTemplate.find('.content')); var popup = monster.ui.dialog(featureTemplate, { title: currentUser.extra.mapFeatures.hotdesk.title, position: ['center', 20] }); }, usersRenderVMToEmail: function(currentUser) { var self = this, featureTemplate = $(monster.template(self, 'users-feature-vm_to_email', currentUser)), switchFeature = featureTemplate.find('.switch').bootstrapSwitch(), featureForm = featureTemplate.find('#vm_to_email_form'); monster.ui.validate(featureForm); featureTemplate.find('.cancel-link').on('click', function() { popup.dialog('close').remove(); }); switchFeature.on('switch-change', function(e, data) { data.value ? featureTemplate.find('.content').slideDown() : featureTemplate.find('.content').slideUp(); }); featureTemplate.find('.save').on('click', function() { var formData = form2object('vm_to_email_form'), userToSave = $.extend(true, {}, currentUser), enabled = switchFeature.bootstrapSwitch('status'), args = { callback: function() { popup.dialog('close').remove(); }, openedTab: 'features' }, updateUser = function(user) { self.usersUpdateUser(user, function(data) { args.userId = data.data.id; self.usersRender(args); }); }, /* updates all the vmboxes with the new delete after notify setting, and then calls the callback*/ updateVMsDeleteAfterNotify = function(val, userId, callbackAfterUpdate) { self.usersListVMBoxesUser(userId, function(vmboxes) { var listFnParallel = []; _.each(vmboxes, function(vm) { listFnParallel.push(function(callback) { self.usersGetVMBox(vm.id, function(data) { /* Only update vms if the deleteAfterNotify value is different than before */ if(data.delete_after_notify !== val) { data.delete_after_notify = val; self.usersUpdateVMBox(data, function(data) { callback(null, data); }); } else { callback(null, data); } }); }); }); monster.parallel(listFnParallel, function(err, results) { callbackAfterUpdate && callbackAfterUpdate(results); }); }); }; userToSave.vm_to_email_enabled = enabled; /* Only update the email and the checkboxes if the setting is enabled */ if(enabled === true) { if(monster.ui.valid(featureForm)) { userToSave.email = formData.email; /* Update VMBoxes, then update user and finally close the popup */ updateVMsDeleteAfterNotify(formData.delete_after_notify, userToSave.id, function() { updateUser(userToSave); }); } } else { updateUser(userToSave); } }); monster.ui.prettyCheck.create(featureTemplate.find('.content')); var popup = monster.ui.dialog(featureTemplate, { title: currentUser.extra.mapFeatures.vm_to_email.title, position: ['center', 20] }); }, usersRenderCallerId: function(currentUser) { var self = this, featureTemplate = $(monster.template(self, 'users-feature-caller_id', currentUser)), switchFeature = featureTemplate.find('.switch').bootstrapSwitch(); featureTemplate.find('.cancel-link').on('click', function() { popup.dialog('close').remove(); }); switchFeature.on('switch-change', function(e, data) { data.value ? featureTemplate.find('.content').slideDown() : featureTemplate.find('.content').slideUp(); }); featureTemplate.find('.save').on('click', function() { var switchCallerId = featureTemplate.find('.switch'), userData = currentUser, userToSave = $.extend(true, {}, { caller_id: { internal: {}, external: {}, } }, currentUser), args = { openedTab: 'features', callback: function() { popup.dialog('close').remove(); } }; if(switchCallerId.bootstrapSwitch('status') === false) { if('internal' in userToSave.caller_id) { delete userToSave.caller_id.internal.number; } } else { var callerIdValue = featureTemplate.find('.caller-id-select').val(); userToSave.caller_id.internal.number = callerIdValue; userToSave.caller_id.external.number = callerIdValue; } self.usersUpdateUser(userToSave, function(data) { args.userId = data.data.id; self.usersRender(args); }); }); if(currentUser.extra.listCallerId.length > 0){ var popup = monster.ui.dialog(featureTemplate, { title: currentUser.extra.mapFeatures.caller_id.title, position: ['center', 20] }); } else { monster.ui.alert('error', self.i18n.active().users.errorCallerId); } }, usersRenderCallForward: function(currentUser) { var self = this, featureTemplate = $(monster.template(self, 'users-feature-call_forward', currentUser)), switchFeature = featureTemplate.find('.switch').bootstrapSwitch(), featureForm = featureTemplate.find('#call_forward_form'), args = { callback: function() { popup.dialog('close').remove() }, openedTab: 'features' }; monster.ui.validate(featureForm); featureTemplate.find('.cancel-link').on('click', function() { popup.dialog('close').remove(); }); switchFeature.on('switch-change', function(e, data) { data.value ? featureTemplate.find('.content').slideDown() : featureTemplate.find('.content').slideUp(); }); featureTemplate.find('#phoneType').on('change', function() { if ( $(this).val() === 'mobile' ) { featureTemplate.find('#number').mask('+1 (999) 999-9999'); } else if ( $(this).val() === 'deskphone' ) { featureTemplate.find('#number').mask('(999) 999-9999'); } }); featureTemplate.find('.save').on('click', function() { if(monster.ui.valid(featureForm)) { var formData = form2object('call_forward_form'); formData.enabled = switchFeature.bootstrapSwitch('status'); formData.number = monster.util.unformatPhoneNumber(formData.number, 'keepPlus'); delete formData.phoneType; var userToSave = $.extend(true, {}, currentUser, { call_forward: formData}); self.usersUpdateUser(userToSave, function(data) { args.userId = data.data.id; self.usersRender(args); }); } }); monster.ui.prettyCheck.create(featureTemplate.find('.content')); if ( currentUser.call_forward.number && /^(\+1)/.test(currentUser.call_forward.number) ) { featureTemplate.find('#phoneType').val('mobile'); featureTemplate.find('#number').mask('+1 (999) 999-9999'); } else { featureTemplate.find('#phoneType').val('deskphone'); featureTemplate.find('#number').mask('(999) 999-9999'); } var popup = monster.ui.dialog(featureTemplate, { title: currentUser.extra.mapFeatures.call_forward.title, position: ['center', 20] }); }, usersRenderFindMeFollowMe: function(params) { var self = this; if(!params.userCallflow) { monster.ui.alert('error', self.i18n.active().users.find_me_follow_me.noNumber); } else if(!params.userDevices || params.userDevices.length === 0) { monster.ui.alert('error', self.i18n.active().users.find_me_follow_me.noDevice); } else { var currentUser = params.currentUser, userDevices = monster.util.sort(params.userDevices, 'name'), userCallflow = params.userCallflow, featureTemplate = $(monster.template(self, 'users-feature-find_me_follow_me', { currentUser: currentUser, devices: userDevices })), switchFeature = featureTemplate.find('.switch').bootstrapSwitch(), featureForm = featureTemplate.find('#find_me_follow_me_form'), args = { callback: function() { popup.dialog('close').remove(); }, openedTab: 'features' }, selectedDevices = {}; if(userCallflow.flow.module === 'ring_group') { _.each(userCallflow.flow.data.endpoints, function(val) { selectedDevices[val.id] = val; }); } featureTemplate.find('.cancel-link').on('click', function() { popup.dialog('close').remove(); }); switchFeature.on('switch-change', function(e, data) { data.value ? featureTemplate.find('.content').slideDown() : featureTemplate.find('.content').slideUp(); }); featureTemplate.find('.save').on('click', function() { var enabled = switchFeature.bootstrapSwitch('status'), enabledDevices = featureTemplate.find('.device-row[data-device_id]:not(.disabled)'); currentUser.smartpbx = currentUser.smartpbx || {}; currentUser.smartpbx.find_me_follow_me = currentUser.smartpbx.find_me_follow_me || {}; currentUser.smartpbx.find_me_follow_me.enabled = (enabled && enabledDevices.length > 0); if(enabled && enabledDevices.length > 0) { userCallflow.flow.module = 'ring_group'; userCallflow.flow.data = { strategy: "simultaneous", timeout: 20, endpoints: [] } $.each(enabledDevices, function() { var $row = $(this), deviceId = $row.data('device_id'), values = $row.find('.slider-time').slider('values'); userCallflow.flow.data.endpoints.push({ id: deviceId, endpoint_type: "device", delay: values[0], timeout: (values[1] - values[0]) }); if(values[1] > userCallflow.flow.data.timeout) { userCallflow.flow.data.timeout = values[1]; } }); } else { userCallflow.flow.module = 'user'; userCallflow.flow.data = { can_call_self: false, id: currentUser.id, timeout: 20 } } monster.parallel({ callflow: function(callbackParallel) { self.usersUpdateCallflow(userCallflow, function(data) { callbackParallel && callbackParallel(null, data.data); }); }, user: function(callbackParallel) { self.usersUpdateUser(currentUser, function(data) { callbackParallel && callbackParallel(null, data.data); }); } }, function(err, results) { args.userId = results.user.id; if(typeof params.saveCallback === 'function') { params.saveCallback(args); } else { self.usersRender(args); } } ); }); monster.ui.prettyCheck.create(featureTemplate.find('.disable-device')); var popup = monster.ui.dialog(featureTemplate, { title: currentUser.extra.mapFeatures.find_me_follow_me.title, position: ['center', 20] }); featureTemplate.find('.disable-device').on('ifToggled', function() { var parentRow = $(this).parents('.device-row'); if(this.checked) { parentRow.find('.times').stop().animate({ opacity: 0 }); parentRow.addClass('disabled') } else { parentRow.find('.times').stop().animate({ opacity: 1 }); parentRow.removeClass('disabled') } }); featureTemplate.find('.distribute-button').on('click', function() { var sliders = featureTemplate.find('.slider-time') max = sliders.first().slider('option', 'max'), section = Math.floor(max/sliders.length), current = 0; monster.ui.prettyCheck.action(featureTemplate.find('.device-row .disable-device'), 'uncheck'); $.each(sliders, function() { $(this).slider('values', [current, current+=section]); }); }); featureTemplate.on('click', '.device-row.title .scale-max', function() { var $this = $(this), input = $this.siblings('.scale-max-input'); input.show(); input.focus(); $this.hide(); }); featureTemplate.on('blur', '.device-row.title .scale-max-input', function(e) { var $this = $(this), value = $this.val(), intValue = parseInt($this.val()); if(value != $this.data('current') && !isNaN(intValue) && intValue >= 30) { self.usersRenderFindMeFollowMeSliders(featureTemplate, userDevices, selectedDevices, intValue); } else { $this.val($this.data('current')).hide(); $this.siblings('.scale-max').show(); } }); featureTemplate.on('keydown', '.device-row.title .scale-max-input', function(e) { switch(e.keyCode) { case 27: $(this).val(-1); case 13: e.preventDefault(); $(this).blur(); break; } }); self.usersRenderFindMeFollowMeSliders(featureTemplate, userDevices, selectedDevices); } }, usersRenderFindMeFollowMeSliders: function(template, deviceList, ringGroup, maxSeconds) { var self = this, scaleSections = 6, //Number of 'sections' in the time scales for the sliders scaleMaxSeconds = maxSeconds && maxSeconds >= 30 ? maxSeconds : 120; //Maximum of seconds, corresponding to the end of the scale if(!maxSeconds) { var currentMax = 0; _.each(ringGroup, function(endpoint) { currentMax = (endpoint.delay+endpoint.timeout > currentMax) ? endpoint.delay+endpoint.timeout : currentMax; }); scaleMaxSeconds = currentMax > scaleMaxSeconds ? Math.ceil(currentMax/60)*60 : scaleMaxSeconds; } var sliderTooltip = function(event, ui) { var val = ui.value, tooltip = ''; $(ui.handle).html(tooltip); }, createTooltip = function(event, ui, deviceId, sliderObj) { var val1 = sliderObj.slider('values', 0), val2 = sliderObj.slider('values', 1), tooltip1 = '', tooltip2 = ''; template.find('.device-row[data-device_id="'+ deviceId + '"] .slider-time .ui-slider-handle').first().html(tooltip1); template.find('.device-row[data-device_id="'+ deviceId + '"] .slider-time .ui-slider-handle').last().html(tooltip2); }, createSlider = function(device) { var deviceRow = template.find('.device-row[data-device_id="'+ device.id +'"]'); deviceRow.find('.slider-time').slider({ range: true, min: 0, max: scaleMaxSeconds, values: device.id in ringGroup ? [ ringGroup[device.id].delay, ringGroup[device.id].delay+ringGroup[device.id].timeout ] : [0,0], slide: sliderTooltip, change: sliderTooltip, create: function(event, ui) { createTooltip(event, ui, device.id, $(this)); }, }); createSliderScale(deviceRow); }, createSliderScale = function(container, isHeader) { var scaleContainer = container.find('.scale-container') isHeader = isHeader || false; scaleContainer.empty(); for(var i=1; i<=scaleSections; i++) { var toAppend = '