PageSourceSearch

https://twork-t.co.jp/shop_lp/js/chatbot/botui.js

js twork-t.co.jp collected 2026-10-02 01:04:11 UTC 18,834 bytes, 419 lines download raw bytes

1/*
2 * botui 0.3.8
3 * A JS library to build the UI for your bot
4 * https://botui.org
5 *
6 * Copyright 2019, Moin Uddin
7 * Released under the MIT license.
8*/
9
10(function (root, factory) {
11  "use strict";
12  if (typeof define === 'function' && define.amd) {
13    define([], function () {
14      return (root.BotUI = factory(root));
15    });
16  } else {
17    root.BotUI = factory(root);
18  }
19}(typeof window !== 'undefined' ? window : this, function (root, undefined) {
20  "use strict";
21
22  var BotUI = (function (id, opts) {
23
24    opts = opts || {};
25
26    if(!id) {
27      throw Error('BotUI: Container id is required as first argument.');
28    }
29
30    if(!document.getElementById(id)) {
31      throw Error('BotUI: Element with id #' + id + ' does not exist.');
32    }
33
34    if(!root.Vue && !opts.vue) {
35      throw Error('BotUI: Vue is required but not found.');
36    }
37
38    var _botApp, // current vue instance.
39    _options = {
40      debug: false,
41      fontawesome: true,
42      searchselect: true
43    },
44    _container, // the outermost Element. Needed to scroll to bottom, for now.
45    _interface = {}, // methods returned by a BotUI() instance.
46    _actionResolve,
47    _markDownRegex = {
48      icon: /!\(([^\)]+)\)/igm, // !(icon)
49      image: /!\[(.*?)\]\((.*?)\)/igm, // ![aleternate text](src)
50      link: /\[([^\[]+)\]\(([^\)]+)\)(\^?)/igm // [text](link) ^ can be added at end to set the target as 'blank'
51    },
52    _fontAwesome = 'https://use.fontawesome.com/ea731dcb6f.js',
53    _esPromisePollyfill = 'https://cdn.jsdelivr.net/es6-promise/4.1.0/es6-promise.min.js', // mostly for IE
54    _searchselect =  "https://unpkg.com/[email protected]/dist/vue-select.js";
55
56    root.Vue = root.Vue || opts.vue;
57
58    // merge opts passed to constructor with _options
59    for (var prop in _options) {
60      if (opts.hasOwnProperty(prop)) {
61        _options[prop] = opts[prop];
62      }
63    }
64
65    if(!root.Promise && typeof Promise === "undefined" && !opts.promise) {
66      loadScript(_esPromisePollyfill);
67    }
68
69    function _linkReplacer(match, $1, $2, $3) {
70      var _target = $3 ? 'blank' : ''; // check if '^' sign is present with link syntax
71      return "<a class='botui-message-content-link' target='" + _target + "' href='" + $2 +"'>" + $1 + "</a>";
72    }
73
74    function _parseMarkDown(text) {
75      return text
76                 .replace(_markDownRegex.image, "<img class='botui-message-content-image' src='$2' alt='$1' />")
77                 .replace(_markDownRegex.icon, "<i class='botui-icon botui-message-content-icon fa fa-$1'></i>")
78                 .replace(_markDownRegex.link, _linkReplacer);
79    }
80
81    function loadScript(src, cb) {
82      var script = document.createElement('script');
83          script.type = 'text/javascript';
84          script.src = src;
85
86          if(cb) {
87            script.onload = cb;
88          }
89
90      document.body.appendChild(script);
91    }
92
93    function _handleAction(text) {
94      if(_instance.action.addMessage) {
95        _interface.message.human({
96          delay: 100,
97          content: text
98        });
99      }
100      _instance.action.show = !_instance.action.autoHide;
101    }
102
103    var _botuiComponent = {
104      template: '<div class=\"botui botui-container\" v-botui-container><div class=\"botui-messages-container\"><div v-for=\"msg in messages\" class=\"botui-message\" :class=\"msg.cssClass\" v-botui-scroll><transition name=\"slide-fade\"><div v-if=\"msg.visible\"><div v-if=\"msg.photo && !msg.loading\" :class=\"[\'profil\', \'profile\', {human: msg.human, \'agent\': !msg.human}]\"> <img :src=\"msg.photo\" :class=\"[{human: msg.human, \'agent\': !msg.human}]\"></div><div :class=\"[{human: msg.human, \'botui-message-content\': true}, msg.type]\"><span v-if=\"msg.type == \'text\'\" v-text=\"msg.content\" v-botui-markdown></span><span v-if=\"msg.type == \'html\'\" v-html=\"msg.content\"></span> <iframe v-if=\"msg.type == \'embed\'\" :src=\"msg.content\" frameborder=\"0\" allowfullscreen></iframe></div></div></transition><div v-if=\"msg.photo && msg.loading && !msg.human\" :class=\"[\'profil\', \'profile\', {human: msg.human, \'agent\': !msg.human}]\"> <img :src=\"msg.photo\" :class=\"[{human: msg.human, \'agent\': !msg.human}]\"></div><div v-if=\"msg.loading\" class=\"botui-message-content loading\"><i class=\"dot\"></i><i class=\"dot\"></i><i class=\"dot\"></i></div></div></div><div class=\"botui-actions-container\"><transition name=\"slide-fade\"><div v-if=\"action.show\" v-botui-scroll><form v-if=\"action.type == \'text\'\" class=\"botui-actions-text\" @submit.prevent=\"handle_action_text()\" :class=\"action.cssClass\"><i v-if=\"action.text.icon\" class=\"botui-icon botui-action-text-icon fa\" :class=\"\'fa-\' + action.text.icon\"></i> <input type=\"text\" ref=\"input\" :type=\"action.text.sub_type\" v-model=\"action.text.value\" class=\"botui-actions-text-input\" :placeholder=\"action.text.placeholder\" :size=\"action.text.size\" :value=\" action.text.value\" :class=\"action.text.cssClass\" required v-focus/> <button type=\"submit\" :class=\"{\'botui-actions-buttons-button\': !!action.text.button, \'botui-actions-text-submit\': !action.text.button}\"><i v-if=\"action.text.button && action.text.button.icon\" class=\"botui-icon botui-action-button-icon fa\" :class=\"\'fa-\' + action.text.button.icon\"></i> <span>{{(action.text.button && action.text.button.label) || \'Go\'}}</span></button></form><form v-if=\"action.type == \'select\'\" class=\"botui-actions-select\" @submit.prevent=\"handle_action_select()\" :class=\"action.cssClass\"><i v-if=\"action.select.icon\" class=\"botui-icon botui-action-select-icon fa\" :class=\"\'fa-\' + action.select.icon\"></i><v-select v-if=\"action.select.searchselect && !action.select.multipleselect\" v-model=\"action.select.value\" :value=\"action.select.value\" :placeholder=\"action.select.placeholder\" class=\"botui-actions-text-searchselect\" :label=\"action.select.label\" :options=\"action.select.options\"></v-select><v-select v-else-if=\"action.select.searchselect && action.select.multipleselect\" multiple v-model=\"action.select.value\" :value=\"action.select.value\" :placeholder=\"action.select.placeholder\" class=\"botui-actions-text-searchselect\" :label=\"action.select.label\" :options=\"action.select.options\"></v-select> <select v-else v-model=\"action.select.value\" class=\"botui-actions-text-select\" :placeholder=\"action.select.placeholder\" :size=\"action.select.size\" :class=\"action.select.cssClass\" required v-focus><option v-for=\"option in action.select.options\" :class=\"action.select.optionClass\" v-bind:value=\"option.value\" :disabled=\"(option.value == \'\')?true:false\" :selected=\"(action.select.value == option.value)?\'selected\':\'\'\"> {{ option.text }}</option></select> <button type=\"submit\" :class=\"{\'botui-actions-buttons-button\': !!action.select.button, \'botui-actions-select-submit\': !action.select.button}\"><i v-if=\"action.select.button && action.select.button.icon\" class=\"botui-icon botui-action-button-icon fa\" :class=\"\'fa-\' + action.select.button.icon\"></i> <span>{{(action.select.button && action.select.button.label) || \'Ok\'}}</span></button></form><div v-if=\"action.type == \'button\'\" class=\"botui-actions-buttons\" :class=\"action.cssClass\"> <button type=\"button\" :class=\"button.cssClass\" class=\"botui-actions-buttons-button\" v-for=\"button in action.button.buttons\" @click=\"handle_action_button(button)\"><i v-if=\"button.icon\" class=\"botui-icon botui-action-button-icon fa\" :class=\"\'fa-\' + button.icon\"></i> {{button.text}}</button></div><form v-if=\"action.type == \'buttontext\'\" class=\"botui-actions-text\" @submit.prevent=\"handle_action_text()\" :class=\"action.cssClass\"><i v-if=\"action.text.icon\" class=\"botui-icon botui-action-text-icon fa\" :class=\"\'fa-\' + action.text.icon\"></i> <input type=\"text\" ref=\"input\" :type=\"action.text.sub_type\" v-model=\"action.text.value\" class=\"botui-actions-text-input\" :placeholder=\"action.text.placeholder\" :size=\"action.text.size\" :value=\"action.text.value\" :class=\"action.text.cssClass\" required v-focus/> <button type=\"submit\" :class=\"{\'botui-actions-buttons-button\': !!action.text.button, \'botui-actions-text-submit\': !action.text.button}\"><i v-if=\"action.text.button && action.text.button.icon\" class=\"botui-icon botui-action-button-icon fa\" :class=\"\'fa-\' + action.text.button.icon\"></i> <span>{{(action.text.button && action.text.button.label) || \'Go\'}}</span></button><div class=\"botui-actions-buttons\" :class=\"action.cssClass\"> <button type=\"button\" :class=\"button.cssClass\" class=\"botui-actions-buttons-button\" v-for=\"button in action.button.buttons\" @click=\"handle_action_button(button)\" autofocus><i v-if=\"button.icon\" class=\"botui-icon botui-action-button-icon fa\" :class=\"\'fa-\' + button.icon\"></i> {{button.text}}</button></div></form></div></transition></div></div>', // replaced by HTML template during build. see Gulpfile.js
105      data: function () {
106        return {
107          action: {
108            text: {
109              size: 30,
110              placeholder: 'Write here ..'
111            },
112            button: {},
113            show: false,
114            type: 'text',
115            autoHide: true,
116            addMessage: true
117          },
118          messages: []
119        };
120      },
121      computed: {
122        isMobile: function () {
123          return root.innerWidth && root.innerWidth <= 768;
124        }
125      },
126    	methods: {
127    		handle_action_button: function (button) {
128          for (var i = 0; i < this.action.button.buttons.length; i++) {
129            if(this.action.button.buttons[i].value == button.value && typeof(this.action.button.buttons[i].event) == 'function') {
130              this.action.button.buttons[i].event(button);
131              if (this.action.button.buttons[i].actionStop) return false;
132              break;
133            }
134          }
135
136          _handleAction(button.text);
137
138          var defaultActionObj = {
139            type: 'button',
140            text: button.text,
141            value: button.value
142          };
143
144          for (var eachProperty in button) {
145            if (button.hasOwnProperty(eachProperty)) {
146              if (eachProperty !== 'type' && eachProperty !== 'text' && eachProperty !== 'value') {
147                defaultActionObj[eachProperty] = button[eachProperty];
148              }
149            }
150          }
151
152          _actionResolve(defaultActionObj);
153    		},
154    		handle_action_text: function () {
155    			if(!this.action.text.value) return;
156          _handleAction(this.action.text.value);
157    			_actionResolve({
158            type: 'text',
159            value: this.action.text.value
160          });
161    			this.action.text.value = '';
162    		},
163        handle_action_select: function () {
164          if(this.action.select.searchselect && !this.action.select.multipleselect) {
165            if(!this.action.select.value.value) return;
166            _handleAction(this.action.select.value[this.action.select.label]);
167            _actionResolve({
168              type: 'text',
169              value: this.action.select.value.value,
170              text: this.action.select.value.text,
171              obj: this.action.select.value
172            });
173          }
174          if(this.action.select.searchselect && this.action.select.multipleselect) {
175            if(!this.action.select.value) return;
176            var values = new Array();
177            var labels = new Array();
178            for (var i = 0; i < this.action.select.value.length; i++) {
179              values.push(this.action.select.value[i].value);
180              labels.push(this.action.select.value[i][this.action.select.label]);
181            }
182            _handleAction(labels.join(', '));
183            _actionResolve({
184              type: 'text',
185              value: values.join(', '),
186              text: labels.join(', '),
187              obj: this.action.select.value
188            });
189          }
190          else {
191            if(!this.action.select.value) return;
192            for (var i = 0; i < this.action.select.options.length; i++) { // Find select title
193              if (this.action.select.options[i].value == this.action.select.value) {
194                _handleAction(this.action.select.options[i].text);
195                _actionResolve({
196                  type: 'text',
197                  value: this.action.select.value,
198                  text: this.action.select.options[i].text
199                });
200              }
201            }
202          }
203        }
204    	}
205    };
206
207    root.Vue.directive('botui-markdown', function (el, binding) {
208      if(binding.value == 'false') return; // v-botui-markdown="false"
209      el.innerHTML = _parseMarkDown(el.textContent);
210    });
211
212    root.Vue.directive('botui-scroll', {
213      inserted: function (el) {
214        _container.scrollTop = _container.scrollHeight;
215      }
216    });
217
218    root.Vue.directive('focus', {
219      inserted: function (el) {
220        el.focus();
221      }
222    });
223
224    root.Vue.directive('botui-container', {
225      inserted: function (el) {
226        _container = el;
227      }
228    });
229
230    _botApp = new root.Vue({
231      components: {
232        'bot-ui': _botuiComponent
233      }
234    }).$mount('#' + id);
235
236    var _instance = _botApp.$children[0]; // to access the component's data
237
238    function _addMessage(_msg) {
239
240      if(!_msg.loading && !_msg.content) {
241        throw Error('BotUI: "content" is required in a non-loading message object.');
242      }
243
244      _msg.type = _msg.type || 'text';
245      _msg.visible = (_msg.delay || _msg.loading) ? false : true;
246      var _index = _instance.messages.push(_msg) - 1;
247
248      return new Promise(function (resolve, reject) {
249        setTimeout(function () {
250          if(_msg.delay) {
251            _msg.visible = true;
252
253            if(_msg.loading) {
254              _msg.loading = false;
255            }
256          }
257          resolve(_index);
258        }, _msg.delay || 0);
259      });
260    }
261
262    function _checkOpts(_opts) {
263      if(typeof _opts === 'string') {
264        _opts = {
265          content: _opts
266        };
267      }
268      return _opts || {};
269    }
270
271    _interface.message =  {
272      add: function (addOpts) {
273        return _addMessage( _checkOpts(addOpts) );
274      },
275      bot: function (addOpts) {
276        addOpts = _checkOpts(addOpts);
277        return _addMessage(addOpts);
278      },
279      human: function (addOpts) {
280        addOpts = _checkOpts(addOpts);
281        addOpts.human = true;
282        return _addMessage(addOpts);
283      },
284      get: function (index) {
285        return Promise.resolve(_instance.messages[index]);
286      },
287      remove: function (index) {
288        _instance.messages.splice(index, 1);
289        return Promise.resolve();
290      },
291      update: function (index, msg) { // only content can be updated, not the message type.
292        var _msg = _instance.messages[index];
293        _msg.content = msg.content;
294        _msg.visible = !msg.loading;
295        _msg.loading = !!msg.loading;
296        return Promise.resolve(msg.content);
297      },
298      removeAll: function () {
299        _instance.messages.splice(0, _instance.messages.length);
300        return Promise.resolve();
301      }
302    };
303
304    function mergeAtoB(objA, objB) {
305      for (var prop in objA) {
306        if (!objB.hasOwnProperty(prop)) {
307          objB[prop] = objA[prop];
308        }
309      }
310    }
311
312    function _checkAction(_opts) {
313      if(!_opts.action && !_opts.actionButton  && !_opts.actionText) {
314        throw Error('BotUI: "action" property is required.');
315      }
316    }
317
318    function _showActions(_opts) {
319
320      _checkAction(_opts);
321
322      mergeAtoB({
323        type: 'text',
324        cssClass: '',
325        autoHide: true,
326        addMessage: true
327      }, _opts);
328
329      _instance.action.type = _opts.type;
330      _instance.action.cssClass = _opts.cssClass;
331      _instance.action.autoHide = _opts.autoHide;
332      _instance.action.addMessage = _opts.addMessage;
333
334      return new Promise(function(resolve, reject) {
335        _actionResolve = resolve; // resolved when action is performed, i.e: button clicked, text submitted, etc.
336        setTimeout(function () {
337          _instance.action.show = true;
338        }, _opts.delay || 0);
339      });
340    };
341
342    _interface.action = {
343      show: _showActions,
344      hide: function () {
345        _instance.action.show = false;
346        return Promise.resolve();
347      },
348      text: function (_opts) {
349        _checkAction(_opts);
350        _instance.action.text = _opts.action;
351        return _showActions(_opts);
352      },
353      button: function (_opts) {
354        _checkAction(_opts);
355        _opts.type = 'button';
356        _instance.action.button.buttons = _opts.action;
357        return _showActions(_opts);
358      },
359      select: function (_opts) {
360        _checkAction(_opts);
361        _opts.type = 'select';
362        _opts.action.label = _opts.action.label || 'text';
363        _opts.action.value = _opts.action.value || '';
364        _opts.action.searchselect = typeof _opts.action.searchselect !== 'undefined' ? _opts.action.searchselect : _options.searchselect;
365        _opts.action.multipleselect = _opts.action.multipleselect || false;
366        if (_opts.action.searchselect && typeof(_opts.action.value) == 'string') {
367          if (!_opts.action.multipleselect) {
368            for (var i = 0; i < _opts.action.options.length; i++) { // Find object
369              if (_opts.action.options[i].value == _opts.action.value) {
370                _opts.action.value = _opts.action.options[i]
371              }
372            }
373          }
374          else {
375            var vals = _opts.action.value.split(',');
376            _opts.action.value = new Array();
377            for (var i = 0; i < _opts.action.options.length; i++) { // Find object
378              for (var j = 0; j < vals.length; j++) { // Search values
379                if (_opts.action.options[i].value == vals[j]) {
380                  _opts.action.value.push(_opts.action.options[i]);
381                }
382              }
383            }
384          }
385        }
386        if (!_opts.action.searchselect) { _opts.action.options.unshift({value:'',text : _opts.action.placeholder}); }
387        _instance.action.button = _opts.action.button;
388        _instance.action.select = _opts.action;
389        return _showActions(_opts);
390      },
391      buttontext: function (_opts) {
392        _checkAction(_opts);
393        _opts.type = 'buttontext';
394        _instance.action.button.buttons = _opts.actionButton;
395        _instance.action.text = _opts.actionText;
396        return _showActions(_opts);
397      }
398    };
399
400    if(_options.fontawesome) {
401      loadScript(_fontAwesome);
402    }
403
404    if(_options.searchselect) {
405      loadScript(_searchselect, function() {
406        Vue.component('v-select', VueSelect.VueSelect);
407      });
408    }
409
410    if(_options.debug) {
411      _interface._botApp = _botApp; // current Vue instance
412    }
413
414    return _interface;
415  });
416
417  return BotUI;
418
419}
vendor: 4 bytes, line 419
419));

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.