­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ /** * This file creates drag and drop feature for Giga Messenger Bot * * @param jQuery $ Alias of jQuery * @param Angular angular Alias of Angular * * @return void */ ;(function ($, angular) { function sanitizeButton(button) { if (['web_url', 'account_link', 'account_unlink', 'element_share'].indexOf(button.type) !== -1) { delete button.payload; } if (['postback', 'phone_number', 'account_unlink', 'element_share', 'nested'].indexOf(button.type) !== -1) { delete button.url; delete button.messenger_extensions; delete button.webview_height_ratio; delete button.fallback_url; } if (['account_link', 'account_unlink', 'element_share'].indexOf(button.type) !== -1) { delete button.title; } if (button.type === 'nested') { button.call_to_actions = []; } return button; } function recursiveRemove(collection, item) { collection.call_to_actions.forEach(function (element, index) { if (element === item) { collection.call_to_actions.splice(index, 1); } if (typeof element.call_to_actions != 'undefined') { recursiveRemove(element, item); } }); } 'use strict'; // Create an app named `Bot` var app = angular.module('Bot', ['ui.tree']); app.controller('BotController', function ($scope, $window, $http) { $scope.isLoading = false; // The node format of a Bot $scope.defaultNode = { type: 'text', pattern: '', answers: [ { text: '' } ] }; $scope.node = {}; // Payloads buttons $scope.payloads = []; $scope.nodes = []; $scope.answersType = ['text']; $scope.showMessage = false; $scope.waits = []; $scope.loginUrl = ''; // For Subscription Module $scope.messages = []; $scope.search = ''; $scope.leads = []; $scope.added = []; $scope.queued = []; $scope.activeAnswer = 0; /** * This method runs on page load. Load the required data. * * @return void */ $scope.init = function () { var required = ['nodes', 'payloads', 'waits', 'channels']; angular.forEach(required, function (dependency) { if (typeof $window[dependency] != 'undefined') { $scope[dependency] = $window[dependency]; } }); $scope.loginUrl = $window.loginUrl; $scope.node = angular.copy($scope.defaultNode); }; /** * Init Method for Subscription Builder * * @return void */ $scope.initMessageBuilder = function () { if (typeof $window.channels != 'undefined') { $scope.channels = $window.channels; } $scope.node = angular.copy($scope.defaultNode); if (typeof $window.answers != 'undefined') { $scope.node.answers = $window.answers; $scope.answersType = $scope.getAnswersTypeFromNode($scope.node); } }; $scope.treeOptions = { dropped: function () { $scope.answersType = $scope.getAnswersTypeFromNode($scope.node); } }; /** * Add default node content * * @return void */ $scope.addAnswer = function () { $scope.unedit(); $scope.node.answers.push({ text: '' }); $scope.activeAnswer = $scope.node.answers.length - 1; $scope.answersType.push('text'); }; /** * Toggle edit answer box * @param index */ $scope.editAnswer = function (index) { $scope.activeAnswer = ($scope.activeAnswer === index) ? null : index; }; /** * Close edit answer box */ $scope.unedit = function () { $scope.activeAnswer = null; }; /** * Action runs when Add Button clicked * * @param answer Response */ $scope.addButton = function (answer) { if (typeof answer.attachment.payload.buttons === 'undefined') { answer.attachment.payload.buttons = []; } answer.attachment.payload.buttons.push({ 'type': 'web_url', 'title': '', 'url': '' }); }; /** * Action runs when Add Button on Generic Template clicked * * @param bubble Bubble node */ $scope.addGenericButton = function (bubble) { // If buttons doesn't exists. Create it. if (typeof bubble['buttons'] === 'undefined') bubble['buttons'] = []; bubble['buttons'].push({ 'type': 'web_url', 'title': '', 'url': '' }); }; $scope.addQuickReply = function (answer) { // If buttons doesn't exists. Create it. if (typeof answer['quick_replies'] === 'undefined') { answer['quick_replies'] = []; } answer.quick_replies.push({ 'content_type': 'text', 'title': '', 'payload': '' }); }; $scope.removeQuickReply = function ($index, answer) { answer.quick_replies.splice($index, 1); }; /** * Action runs when Add Bubble clicked * * @param answer Response node */ $scope.addGenericBubble = function (answer) { // If bubble doesn't exists. Create it. if (!angular.isArray(answer.attachment.payload.elements)) { answer.attachment.payload.elements = []; } answer.attachment.payload.elements.push({ 'image_url': '', 'title': '', 'subtitle': '', 'buttons': [] }); }; $scope.removeGenericBubble = function ($index, content) { content.attachment.payload.elements.splice($index, 1); }; /** * When user clicks Edit button on each node. Scroll to top with node content * * @param node node */ $scope.editNode = function (node) { // Callback is an object so we have to cast to array if (!angular.isArray(node.answers)) node.answers = [node.answers]; $scope.answersType = $scope.getAnswersTypeFromNode(node); $scope.node = node; }; /** * Remove button from button group or bubble * * @param $index * @param content * @param bubble */ $scope.removeButton = function ($index, content, bubble) { if (typeof content.buttons != 'undefined') { content.buttons.splice($index, 1); } else { bubble.buttons.splice($index, 1); } }; /** * Remove Draft Response. This doesn't persist data, user have to save changes. * * @param $index */ $scope.removeDraftAnswer = function ($index) { $scope.node.answers.splice($index, 1); }; $scope.getAnswersTypeFromNode = function (node) { var answersType = []; angular.forEach(node.answers, function (answer, index) { if (typeof answer.type != 'undefined') { answersType[index] = answer.type; } if (typeof answer.text != 'undefined') { answersType[index] = 'text'; } if (typeof answer.attachment != 'undefined' && typeof answer.attachment.type != 'undefined') { answersType[index] = answer.attachment.type; if (answer.attachment.type === 'template' && typeof answer.attachment.payload.template_type != 'undefined') { answersType[index] = answer.attachment.payload.template_type; } } }); return answersType; }; $scope.removeNode = function (node, $index) { if (!confirm('This can not be undone. Do you want to continue?')) return false; // Make a post update if (!$scope.isLoading) { $scope.isLoading = true; $http.post($window.ajaxurl + '?action=remove_node', { action: 'remove_node', node_id: node.id }).then(function () { $scope.nodes.splice($index, 1); }); $scope.isLoading = false; } }; $scope.updateNode = function () { $scope.showMessage = false; // Make a post update if (!$scope.isLoading) { $scope.isLoading = true; $http.post($window.ajaxurl + '?action=update_node', { action: 'update_node', node: $scope.node }).then(function (response) { if (typeof $scope.node.id == 'undefined' || !$scope.node.id) { $scope.nodes.unshift(response.data.data); } $scope.node = angular.copy($scope.defaultNode); $scope.answersType = $scope.getAnswersTypeFromNode($scope.node); $scope.showMessage = true; }); $scope.isLoading = false; } }; $scope.onButtonTypeChange = function (button) { sanitizeButton(button); if (button.type === 'account_link') { button.url = $scope.loginUrl; } }; /** * Handle search leads in subscription message form */ $scope.$watch('search', function () { if (!$scope.isLoading && $scope.search.length > 0) { $scope.isLoading = true; $http.get($window.ajaxurl + '?action=search_leads', { params: { name: $scope.search } }).success(function (response) { $scope.queued = response.data; }).error(function (response) { console.log(response.data); }); $scope.isLoading = false; } }); $scope.addLead = function ($index) { var isDuplicated = false; angular.forEach($scope.leads, function (lead) { if (lead.id === $scope.queued[$index].id) { isDuplicated = true; return false; } }); if (isDuplicated) return false; $scope.leads.push($scope.queued[$index]); $scope.queued.splice($index, 1); }; }); app.controller('SettingController', function ($scope, $window) { $scope.supportedLocales = []; $scope.settings = []; $scope.defaultGreeting = [ { locale: 'default', text: 'Hello' } ]; $scope.defaultPersistentMenu = []; $scope.activeLocale = {}; $scope.dragSettings = {}; $scope.field = 'greeting'; $scope.activeMenuItem = {}; $scope.init = function (field) { $scope.field = field; $scope.supportedLocales = $window.supportedLocales; if (typeof $window.defaultPersistentMenu != 'undefined') { $scope.defaultPersistentMenu = $window.defaultPersistentMenu; } $scope.settings = $window.settings; if (!Array.isArray($scope.settings.greeting)) { $scope.settings.greeting = $scope.defaultGreeting; } if (!Array.isArray($scope.settings.persistent_menu)) { $scope.settings.persistent_menu = $scope.defaultPersistentMenu; } $scope.selectLocale('default', $scope.field); }; $scope.selectLocale = function (locale) { var activeLocale = {}, found = false; $scope.settings[$scope.field].forEach(function (greeting) { if (greeting.locale == locale) { activeLocale = greeting; found = true; } }); $scope.activeLocale = activeLocale; if (!found) { $scope.addLocale(locale); $scope.selectLocale(locale); } }; $scope.addLocale = function (locale) { var item = { locale: locale }; if ($scope.field === 'greeting') { item.text = ''; } if ($scope.field === 'persistent_menu') { item.call_to_actions = []; } $scope.settings[$scope.field].push(item); }; $scope.getActiveState = function (locale) { var node = $scope.settings[$scope.field].find(function (g) { return g.locale === locale; }); if (typeof node != 'undefined') { if (typeof node.text != 'undefined' && node.text != '') { return 'is-defined'; } if (typeof node.call_to_actions != 'undefined' && node.call_to_actions.length > 0 || typeof node.composer_input_disabled != 'undefined') { return 'is-defined'; } } return 'inactive'; }; $scope.editMenuItem = function (item) { $scope.activeMenuItem = ($scope.activeMenuItem === item) ? {} : item; }; $scope.unedit = function () { $scope.activeMenuItem = {}; }; $scope.addMenuItem = function () { if (typeof $scope.activeLocale.call_to_actions == 'undefined') { $scope.activeLocale.call_to_actions = []; } $scope.activeLocale.call_to_actions.push({ type: 'postback', payload: 'DEFAULT_PAYLOAD', title: 'Untitled' }); }; $scope.sanitizeMenuItem = function (item) { sanitizeButton(item); }; $scope.removeItem = function (item) { recursiveRemove($scope.activeLocale, item); }; $scope.isNotCorrectedFormat = function () { var notCorrected = false; if ($scope.activeLocale.call_to_actions.length > 3) { notCorrected = true; } $scope.activeLocale.call_to_actions.forEach(function (item) { if (typeof item.call_to_actions != 'undefined') { if (item.call_to_actions.length > 5 || item.call_to_actions.length === 0) { notCorrected = true; } item.call_to_actions.forEach(function (sub) { if (typeof sub.call_to_actions != 'undefined' && sub.call_to_actions.length > 5) { notCorrected = true; } }); } }); return notCorrected; }; }); })(jQuery, angular);