Built motion from commit de2cb856.|2.0.31
[motion2.git] / snippet / scripts / app.a926a3b0.js
1 ! function() {
2     "use strict";
3     angular.module("motion", ["ngAnimate", "ngAria", "ngMessages", "ngMaterial", "ngResource", "ngSanitize", "ngCsv", "ngEmbed", "ngEmojiPicker", "ui.router", "LocalStorageModule"]).constant("STORAGE_PREFIX", "motion_chat").constant("STORAGE_VISITOR", "visitor").constant("STORAGE_LAYOUT", "layout").directive("ngEnter", function() {
4         return function(e, t, n) {
5             t.bind("keydown keypress", function(t) {
6                 13 === t.which && (e.$apply(function() {
7                     e.$eval(n.ngEnter)
8                 }), t.preventDefault())
9             })
10         }
11     })
12 }(),
13 function() {
14     "use strict";
15
16     function e(e, t, n, i, o, r, s, a, l, c, d, m) {
17         function p() {
18             w.visitor && w.visitor.interaction && w.visitor.interaction.id && d.chatInteraction.get({
19                 id: w.visitor.interaction.id
20             }).$promise.then(function(e) {
21                 delete w.errors.getInteraction, e.closed && (c.remove(m), t.$emit("hide"), t.settings.online ? r.go("app.online") : r.go("app.offline"))
22             }).catch(g("getInteraction"))
23         }
24
25         function u() {
26             t.loading = !1, t.settings.showMenu = !0, w.replyMessage = "", y = i(v, 2e3), T = i(p, 1e4), b()
27         }
28
29         function g(e) {
30             return function(t) {
31                 w.errors[e] = t.data, b()
32             }
33         }
34
35         function f(e) {
36             d.chatWebsite.notify(e).$promise.then(function(e) {
37                 delete w.errors.sendMessageError, _.isNil(w.visitor.interaction) && (w.visitor.interaction = {
38                     id: e.interaction.id
39                 }, c.set(m, w.visitor)), x()
40             }).catch(g("sendMessageError"))
41         }
42
43         function v() {
44             w.visitor && w.visitor.interaction && w.visitor.interaction.id && d.chatInteraction.getMessages({
45                 id: w.visitor.interaction.id,
46                 $gte: $ ? ["updatedAt", $].join() : void 0
47             }).$promise.then(function(e) {
48                 if (delete w.errors.getMessagesError, $ = moment().format("YYYY-MM-DD HH:mm:ss"), e.count) {
49                     for (var t = 0; t < e.rows.length; t++) w.messages[e.rows[t].id] = e.rows[t], "out" === e.rows[t].direction && h(e.rows[t].id);
50                     b()
51                 }
52             }).catch(g("getMessagesError"))
53         }
54
55         function h(e) {
56             d.chatMessage.update({
57                 id: e,
58                 read: !0
59             }).$promise.catch(function(e) {
60                 console.error(e)
61             })
62         }
63
64         function x() {
65             S.value = "", w.textareaGrow = !1
66         }
67
68         function b() {
69             n(function() {
70                 var e = o[0].getElementById("chat-content");
71                 e.scrollTop = e.scrollHeight
72             })
73         }
74         var y, T, $, w = this,
75             S = document.getElementById("emoji-area");
76         w.errors = {}, w.messages = {}, w.visitor = c.get(m) || {}, w.$onInit = u, w.$onDestroy = u, w.reply = function(e) {
77             var t = S.value.replace(/\n$/, "");
78             e && 13 === e.keyCode && e.shiftKey ? w.textareaGrow = !0 : e && 13 !== e.keyCode || ("" !== t ? f(_.merge({
79                 body: t
80             }, w.visitor)) : x())
81         }, e.$on("$destroy", function() {
82             i.cancel(y), i.cancel(T), y = null, T = null
83         }), t.$on("$download", function(e, t) {
84             t && t(_.values(w.messages))
85         })
86     }
87     e.$inject = ["$scope", "$rootScope", "$timeout", "$interval", "$document", "$state", "$http", "$q", "$mdDialog", "localStorageService", "api", "STORAGE_VISITOR"], angular.module("motion").controller("ChatIndexController", e)
88 }(),
89 function() {
90     "use strict";
91
92     function e(e, t, n, i, o, r, s, a, l, c) {
93         function d(e) {
94             n.parent.postMessage({
95                 cmd: e
96             }, "*")
97         }
98
99         function m(e) {
100             u.layout.up = e, s.set(l, u.layout), d(e ? "show" : "hide")
101         }
102
103         function p() {
104             return u.visitor.interaction || (u.visitor.interaction = s.get(c).interaction), u.visitor.interaction
105         }
106         var u = this;
107         u.$onInit = function() {
108             u.layout = s.get(l) || {
109                 up: !1
110             }, u.visitor = s.get(c) || {}, m(!!u.layout.up), t.settings.online ? i.go("app.online") : i.go("app.offline")
111         }, u.toggle = m, u.download = function() {
112             var e = r.defer();
113             return s.get(c).interaction && a.chatInteraction.getMessages({
114                 id: p().id
115             }).$promise.then(function(t) {
116                 e.resolve(_.map(t.rows, function(e) {
117                     return {
118                         sender: "in" === e.direction ? "Visitor" + e.ContactId : e.UserId ? "Agent" + e.UserId : "System",
119                         message: e.body,
120                         createdAt: moment(e.createdAt).format("MM/DD/YYYY HH:mm:ss")
121                     }
122                 }))
123             }).catch(function(e) {
124                 console.error(e)
125             }), e.promise
126         }, u.getHeaderShape = function() {
127             return "rounded" === t.settings.header_shape ? "15px" : "0px"
128         }, u.exit = function(e) {
129             var n = o.confirm().textContent("Are you sure?").ok("Ok").cancel("Cancel");
130             o.show(n).then(function() {
131                 if (p()) return a.chatInteraction.update({
132                     id: p().id,
133                     closed: !0,
134                     closedAt: moment().format("YYYY-MM-DD HH:mm:ss")
135                 }).$promise
136             }).then(function() {
137                 s.remove(c), t.$emit("hide"), i.go("app.online")
138             }).catch(function(e) {
139                 console.error(e)
140             })
141         }, t.$on("show", function() {
142             m(!0)
143         }), t.$on("hide", function() {
144             m(!1)
145         })
146     }
147     e.$inject = ["$scope", "$rootScope", "$window", "$state", "$mdDialog", "$q", "localStorageService", "api", "STORAGE_LAYOUT", "STORAGE_VISITOR"], angular.module("motion").controller("IndexController", e)
148 }(),
149 function() {
150     "use strict";
151
152     function e(e, t) {
153         var n = {
154                 baseUrl: e.settings.remote + "/api/"
155             },
156             i = {
157                 id: "@id",
158                 token: e.settings.token
159             };
160         return n.chatWebsite = t(n.baseUrl + "chat/websites/:id", i, {
161             notify: {
162                 method: "POST",
163                 url: n.baseUrl + "chat/websites/:id/notify"
164             },
165             getFields: {
166                 method: "GET",
167                 url: n.baseUrl + "chat/websites/:id/fields"
168             }
169         }), n.chatInteraction = t(n.baseUrl + "chat/interactions/:id", i, {
170             update: {
171                 method: "PUT",
172                 url: n.baseUrl + "chat/interactions/:id"
173             },
174             getMessages: {
175                 method: "GET",
176                 url: n.baseUrl + "chat/interactions/:id/messages"
177             }
178         }), n.chatMessage = t(n.baseUrl + "chat/messages/:id", i, {
179             update: {
180                 method: "PUT",
181                 url: n.baseUrl + "chat/messages/:id"
182             }
183         }), n
184     }
185     e.$inject = ["$rootScope", "$resource"], angular.module("motion").factory("api", e)
186 }(),
187 function() {
188     "use strict";
189
190     function e(e, t) {
191         var n = t.search();
192         e.settings = {
193             cursor: "pointer",
194             hide: !0
195         }, _.forIn(n, function(t, n) {
196             "" === t || _.isNil(t) || ("true" === t && (t = !0), "false" === t && (t = !1), e.settings[n] = t)
197         })
198     }
199
200     function t(e, t, n, i, o) {
201         n.html5Mode(!0), i.setPrefix(o), e.state("app", {
202             url: "/app",
203             abstract: !0
204         }).state("app.online", {
205             url: "/online",
206             templateUrl: "app/online/index.html",
207             controller: "OnlineIndexController as vm"
208         }).state("app.offline", {
209             url: "/offline",
210             templateUrl: "app/offline/index.html",
211             controller: "OfflineIndexController as vm"
212         }).state("app.chat", {
213             url: "/chat",
214             templateUrl: "app/chat/index.html",
215             controller: "ChatIndexController as vm"
216         })
217     }
218     e.$inject = ["$rootScope", "$location"], t.$inject = ["$stateProvider", "$urlRouterProvider", "$locationProvider", "localStorageServiceProvider", "STORAGE_PREFIX"], angular.module("motion").config(t).run(e)
219 }(),
220 function() {
221     "use strict";
222
223     function e(e, t, n, i, o, r, s, a, l, c) {
224         var d = this;
225         d.$onInit = function() {
226             t.settings.showMenu = !1, a.chatWebsite.getFields({
227                 id: t.settings.id,
228                 online: !1
229             }).$promise.then(function(e) {
230                 e.count && (d.fields = e.rows)
231             }).catch(function(e) {
232                 console.error(e)
233             })
234         }, d.submit = function() {
235             r.remove(c), t.$emit("hide"), d.form = {}
236         }, d.toggle = function(e, t) {
237             d.form[e] || (d.form[e] = []);
238             var n = d.form[e].indexOf(t);
239             n > -1 ? d.form[e].splice(n, 1) : d.form[e].push(t)
240         }, d.exists = function(e, t) {
241             return d.form[e] || (d.form[e] = []), d.form[e].indexOf(t) > -1
242         }, d.form = {}
243     }
244     e.$inject = ["$scope", "$rootScope", "$state", "$window", "$timeout", "localStorageService", "$http", "api", "STORAGE_PREFIX", "STORAGE_VISITOR"], angular.module("motion").controller("OfflineIndexController", e)
245 }(),
246 function() {
247     "use strict";
248
249     function e(e, t, n, i, o, r, s, a, l, c) {
250         function d() {
251             return "Anonymous" + _.random(1, 99999)
252         }
253         var m = this,
254             p = null;
255         m.$onInit = function() {
256             r.get(c) && (m.visitor = r.get(c)), m.visitor ? n.go("app.chat") : (m.visitor = {
257                 id: t.settings.id,
258                 mapKey: "firstName",
259                 from: d()
260             }, t.settings.showMenu = !1, a.chatWebsite.getFields({
261                 id: t.settings.id,
262                 online: !0
263             }).$promise.then(function(e) {
264                 e.count ? (p = e.fromKey, m.fields = e.rows) : (r.set(c, m.visitor), n.go("app.chat"))
265             }).catch(function(e) {
266                 console.error(e)
267             }))
268         }, m.submit = function() {
269             for (var e = 0; e < m.fields.length; e++) {
270                 var i = m.fields[e];
271                 i.props && m.form.hasOwnProperty(i.props.title) && (_.isNil(i.variable) || (m.visitor[i.variable] = _.isArray(m.form[i.props.title]) ? m.form[i.props.title].join() : m.form[i.props.title]), _.isNil(i.cmField) || (m.visitor[i.cmField] = _.isArray(m.form[i.props.title]) ? m.form[i.props.title].join() : m.form[i.props.title]), e === p && (_.isNil(t.settings.mapKey) || (m.visitor.mapKey = t.settings.mapKey, m.visitor.from = _.isArray(m.form[i.props.title]) ? m.form[i.props.title].join() : m.form[i.props.title])))
272             }
273             r.set(c, m.visitor), t.loading = !0, n.go("app.chat")
274         }, m.toggle = function(e, t) {
275             m.form[e] || (m.form[e] = []);
276             var n = m.form[e].indexOf(t);
277             n > -1 ? m.form[e].splice(n, 1) : m.form[e].push(t)
278         }, m.exists = function(e, t) {
279             return m.form[e] || (m.form[e] = []), m.form[e].indexOf(t) > -1
280         }, m.form = {}
281     }
282     e.$inject = ["$scope", "$rootScope", "$state", "$window", "$timeout", "localStorageService", "$http", "api", "STORAGE_PREFIX", "STORAGE_VISITOR"], angular.module("motion").controller("OnlineIndexController", e)
283 }(), angular.module("motion").run(["$templateCache", function(e) {
284     "use strict";
285     e.put("app/chat/index.html", '\x3c!-- CHAT CONTENT --\x3e\n<md-content id="chat-content" flex>\n  \x3c!-- CHAT MESSAGES --\x3e\n  <div layout="row" ng-repeat="(key, message) in vm.messages track by message.id" class="md-padding message-row" ng-class="{\'in\': message.direction === \'in\', \'out\': message.direction === \'out\' && message.UserId, \'auto\': message.direction === \'out\' && !message.UserId}">\n\n    <img ng-if="message.direction ===\'out\' && !message.UserId" ng-src="assets/images/avatars/robot0.png" class="avatar" alt="system" />\n    <img ng-if="message.direction ===\'out\' && message.UserId" ng-src="assets/images/avatars/agent0.png" class="avatar" alt="agent" />\n    <img ng-if="message.direction ===\'in\'" ng-src="assets/images/avatars/customer0.png" class="avatar" alt="customer">\n\n    <div class="bubble">\n      <div class="time secondary-text">\n        <span>\n          {{message.direction === \'out\' ? (message.UserId ? \'Agent\' + message.UserId : \'System\') : (vm.visitor.from || \'Visitor\' + message.ContactId)}} - {{message.createdAt | date : \'h:mm\'}}\n        </span>\n      </div>\n      <div ng-class="{\'in\': message.direction === \'in\', \'out\': message.direction ===\'out\' && message.UserId, \'auto\': message.direction ===\'out\' && !message.UserId}">\n        <div ng-bind-html="message.body | embed:vm.emojiOptions" class="message"></div>\n      </div>\n    </div>\n\n  </div>\n  \x3c!-- CHAT MESSAGES --\x3e\n\n  \x3c!-- CHAT ERROR --\x3e\n  <div class="chat-error" ng-repeat="error in vm.errors" layout="row" layout-margin>\n    <i class="mdi mdi-alert mdi-24px mdi-light"></i>\n    <md-tooltip md-direction="top">{{error.message || \'Service temporarily unavailable.\'}}</md-tooltip>\n    <span class="chat-error-message">{{error.message || \'Service temporarily unavailable.\'}}</span>\n  </div>\n  \x3c!-- CHAT ERROR --\x3e\n\n</md-content>\n\x3c!-- / CHAT CONTENT --\x3e\n\n\x3c!-- CHAT FOOTER --\x3e\n<div class="chat-footer flex-noshrink" layout="row" layout-align="center center">\n  \x3c!-- REPLY FORM --\x3e\n  <form ng-submit="vm.reply()" flex class="reply-form" layout="row" layout-align="start center">\n\n    <md-input-container flex md-no-float>\n      <textarea id="emoji-area" ng-keyup="vm.reply($event)" md-no-autogrow ng-model="vm.replyMessage" ng-class="{\'grow\': vm.textareaGrow}" placeholder="Type and hit enter to send message" emoji-picker emoji-attachment-location="bottom right" emoji-menu-location="top left"\n        emoji-popup-button-classes="mdi mdi-emoticon mdi-24px" emoji-assets-path="assets/images/ng-emoji-picker">\n      </textarea>\n    </md-input-container>\n\n    <md-button class="md-fab md-mini" type="submit" aria-label="Send message" translate translate-attr-aria-label="CHAT.SEND_MESSAGE" ng-style="{\'background-color\': \'{{settings.color_button}}\'}">\n      <i class="mdi mdi-send mdi-24px mdi-light"></i>\n    </md-button>\n\n  </form>\n  \x3c!-- / REPLY FORM --\x3e\n</div>\n\x3c!-- / CHAT FOOTER--\x3e\n'), e.put("app/offline/index.html", '\x3c!-- CHAT CONTENT --\x3e\n<md-content id="chat-content" style="height: 444px; padding: 25px;" flex layout-padding ms-scroll>\n  <form  ng-if="vm.fields.length" name="userForm" layout="column" ng-submit="vm.submit()" novalidate>\n    <md-input-container class="md-block" ng-repeat="field in vm.fields | orderBy:\'index\'" ng-switch="field.type">\n      \x3c!-- START textinput --\x3e\n      <div ng-switch-when="input">\n        <label>{{field.props.title}}</label>\n        <input name="{{field.props.title}}" ng-model="vm.form[field.props.title]" type="{{field.config.type}}" ng-required="field.config.required">\n        <div class="hint">{{field.props.helpText}}</div>\n      </div>\n      \x3c!-- END textinput --\x3e\n\n      \x3c!-- START textarea --\x3e\n      <div ng-switch-when="textarea">\n        <label>{{field.props.title}}</label>\n        <textarea name="{{field.props.title}}" ng-model="vm.form[field.props.title]" md-maxlength="150" rows="5"></textarea>\n        <div class="hint">{{field.props.helpText}}</div>\n      </div>\n      \x3c!-- END textarea --\x3e\n\n      \x3c!-- START select --\x3e\n      <div ng-switch-when="chooseFromList">\n        <label>{{field.props.title}}</label>\n        <md-select name="{{field.props.title}}"ng-model="vm.form[field.props.title]"  placeholder="{{field.config.placeholder}}" ng-required="field.config.required">\n          <md-option ng-repeat="option in field.options" ng-value="option.value">{{option.value}}</md-option>\n        </md-select>\n        <div class="hint">{{field.props.helpText}}</div>\n      </div>\n      \x3c!-- END select --\x3e\n\n      \x3c!-- START radio --\x3e\n      <div ng-switch-when="multipleChoices" layout="column">\n        <p md-colors="{color: \'grey\'}">{{field.props.title}}</p>\n        <md-radio-group name="{{field.props.title}}" ng-model="vm.form[field.props.title]" ng-required="field.config.required" layout="{{field.config.direction === \'vertical\' ? \'column\' : \'row\'}}">\n          <md-radio-button ng-repeat="option in field.options" value="{{option.value}}" class="md-primary">{{option.value}}</md-radio-button>\n        </md-radio-group>\n        <div class="hint">{{field.props.helpText}}</div>\n      </div>\n      \x3c!-- END radio --\x3e\n\n      \x3c!-- START checkbox --\x3e\n      <div ng-switch-when="checkboxes" layout="column">\n        <p md-colors="{color: \'grey\'}">{{field.props.title}}</p>\n        <div layout="{{field.config.direction === \'vertical\' ? \'column\' : \'row\'}}">\n          <md-checkbox\n          aria-label="{{field.props.title}}"\n          ng-repeat="option in field.options"\n          ng-checked="vm.exists(field.props.title, option.value)"\n          ng-disabled="!vm.exists(field.props.title, option.value) && field.config.maxSelections === vm.form[field.props.title].length"\n          ng-click="vm.toggle(field.props.title, option.value)"\n          flex>\n            {{option.value}}\n          </md-checkbox>\n        </div>\n      </div>\n      \x3c!-- END checkbox --\x3e\n    </md-input-container>\n\n    <md-button type="submit" class="md-raised" ng-disabled="userForm.$invalid || userForm.$pristine" ng-style="{\'background-color\': \'{{settings.color_button}}\'}">SEND</md-button>\n  </form>\n\n  <md-content layout="row" layout-align="center end">\n    {{ settings.defaultWhiteLabel ? \'Powered By XCALLY\' : settings.whiteLabel }}\n  </md-content>\n\n</md-content>\n\x3c!-- / CHAT CONTENT --\x3e\n'), e.put("app/online/index.html", '\x3c!-- CHAT CONTENT --\x3e\n<md-content id="chat-content" style="height: 444px; padding: 25px;" flex layout-padding ms-scroll>\n  <form  ng-if="vm.fields.length" name="userForm" layout="column" ng-submit="vm.submit()" novalidate>\n\n    <md-input-container class="md-block" ng-repeat="field in vm.fields | orderBy:\'index\'" ng-switch="field.type">\n      \x3c!-- START textinput --\x3e\n      <div ng-switch-when="input">\n        <label>{{field.props.title}}</label>\n        <input name="{{field.props.title}}" ng-model="vm.form[field.props.title]" type="{{field.config.type}}" ng-required="field.config.required">\n        <div class="hint">{{field.props.helpText}}</div>\n      </div>\n      \x3c!-- END textinput --\x3e\n\n      \x3c!-- START textarea --\x3e\n      <div ng-switch-when="textarea">\n        <label>{{field.props.title}}</label>\n        <textarea name="{{field.props.title}}" ng-model="vm.form[field.props.title]" md-maxlength="150" rows="5"></textarea>\n        <div class="hint">{{field.props.helpText}}</div>\n      </div>\n      \x3c!-- END textarea --\x3e\n\n      \x3c!-- START select --\x3e\n      <div ng-switch-when="chooseFromList">\n        <label>{{field.props.title}}</label>\n        <md-select name="{{field.props.title}}"ng-model="vm.form[field.props.title]"  placeholder="{{field.config.placeholder}}" ng-required="field.config.required">\n          <md-option ng-repeat="option in field.options" ng-value="option.value">{{option.value}}</md-option>\n        </md-select>\n        <div class="hint">{{field.props.helpText}}</div>\n      </div>\n      \x3c!-- END select --\x3e\n\n      \x3c!-- START radio --\x3e\n      <div ng-switch-when="multipleChoices" layout="column">\n        <p md-colors="{color: \'grey\'}">{{field.props.title}}</p>\n        <md-radio-group name="{{field.props.title}}" ng-model="vm.form[field.props.title]" ng-required="field.config.required" layout="{{field.config.direction === \'vertical\' ? \'column\' : \'row\'}}">\n          <md-radio-button ng-repeat="option in field.options" value="{{option.value}}" class="md-primary">{{option.value}}</md-radio-button>\n        </md-radio-group>\n        <div class="hint">{{field.props.helpText}}</div>\n      </div>\n      \x3c!-- END radio --\x3e\n\n      \x3c!-- START checkbox --\x3e\n      <div ng-switch-when="checkboxes" layout="column">\n        <p md-colors="{color: \'grey\'}">{{field.props.title}}</p>\n        <div layout="{{field.config.direction === \'vertical\' ? \'column\' : \'row\'}}">\n          <md-checkbox\n          aria-label="{{field.props.title}}"\n          ng-repeat="option in field.options"\n          ng-checked="vm.exists(field.props.title, option.value)"\n          ng-disabled="!vm.exists(field.props.title, option.value) && field.config.maxSelections === vm.form[field.props.title].length"\n          ng-click="vm.toggle(field.props.title, option.value)"\n          flex>\n            {{option.value}}\n          </md-checkbox>\n        </div>\n        <div class="hint">{{field.props.helpText}}</div>\n      </div>\n      \x3c!-- END checkbox --\x3e\n    </md-input-container>\n\n    <md-button type="submit" class="md-raised" ng-disabled="userForm.$invalid || userForm.$pristine" ng-style="{\'background-color\': \'{{settings.color_button}}\'}">{{settings.start_chat_button}}</md-button>\n  </form>\n\n  <md-content layout="row" layout-align="center end" style="background: transparent;">\n    {{ settings.defaultWhiteLabel ? \'Powered By XCALLY\' : settings.whiteLabel }}\n  </md-content>\n\n</md-content>\n\x3c!-- / CHAT CONTENT --\x3e\n')
286 }]);