' +\n\t '# for (var i = 0; i < suggestedActions.length; i++) { #' +\n\t '#:suggestedActions[i].title#' +\n\t '# } #' +\n\t '
'\n\t );\n\n\t var HERO_CARD_TEMPLATE = kendo.template(\n\t '' +\n\t '# if (typeof images !== \"undefined\" && images.length > 0) { #' +\n\t '
![\"#:images[0].alt#\"](\"#:images[0].url#\")
' +\n\t '# } #' +\n\t '
' +\n\t '# if (typeof title !== \"undefined\") { #' +\n\t '
#:title#
' +\n\t '# } #' +\n\t '# if (typeof subtitle !== \"undefined\") { #' +\n\t '
#:subtitle#
' +\n\t '# } #' +\n\t '# if (typeof text !== \"undefined\") { #' +\n\t '
#:text#
' +\n\t '# } #' +\n\t '
' +\n\t '# if (typeof buttons !== \"undefined\" && buttons.length > 0) { #' +\n\t '
' +\n\t '# for (var i = 0; i < buttons.length; i++) { #' +\n\t '#:buttons[i].title#' +\n\t '# } #' +\n\t '
' +\n\t '# } #' +\n\t '
'\n\t );\n\n\t extend(kendo.chat, {\n\t Templates: {},\n\t Components: {}\n\t });\n\n\t kendo.chat.registerTemplate = function(templateName, template) {\n\t kendo.chat.Templates[templateName] = kendo.template(template);\n\t };\n\n\t kendo.chat.getTemplate = function(templateName) {\n\t return kendo.chat.Templates[templateName] || TEXT_MESSAGE_TEMPLATE;\n\t };\n\n\t kendo.chat.registerTemplate(\"text\", TEXT_MESSAGE_TEMPLATE);\n\t kendo.chat.registerTemplate(\"message\", TEXT_MESSAGE_TEMPLATE);\n\t kendo.chat.registerTemplate(\"typing\", TYPING_INDICATOR_TEMPLATE);\n\t kendo.chat.registerTemplate(\"suggestedAction\", SUGGESTED_ACTIONS_TEMPLATE);\n\t kendo.chat.registerTemplate(\"heroCard\", HERO_CARD_TEMPLATE);\n\t kendo.chat.registerTemplate(\"application/vnd.microsoft.card.hero\", HERO_CARD_TEMPLATE);\n\n\t kendo.chat.registerComponent = function(componentName, component) {\n\t kendo.chat.Components[componentName] = component;\n\t };\n\n\t kendo.chat.getComponent = function(componentName) {\n\t return kendo.chat.Components[componentName] || null;\n\t };\n\n\t var Component = kendo.chat.Component = kendo.Class.extend({\n\t init: function(options, view) {\n\t this.element = $('\")\n\t .addClass(viewStyles.messageListContent)\n\t .appendTo(this.element);\n\t },\n\n\t _attachEvents: function() {\n\t var styles = ChatView.styles;\n\n\t this.element\n\t .on(\"click\" + NS, proxy(this._listClick, this))\n\t .on(\"click\" + NS, DOT + styles.message, proxy(this._messageClick, this))\n\t .on(\"click\" + NS, DOT + styles.suggestedAction, proxy(this._suggestedActionClick, this))\n\t .on(\"click\" + NS, DOT + styles.cardAction + SPACE + DOT + styles.button, proxy(this._cardActionClick, this));\n\t },\n\n\t _scrollable: function() {\n\t var viewStyles = ChatView.styles;\n\n\t this.element\n\t .on(\"click\" + NS, DOT + viewStyles.cardDeckScrollWrap + SPACE + DOT + viewStyles.button, proxy(this._scrollButtonClick, this));\n\t },\n\n\t _scrollButtonClick: function(e) {\n\t var viewStyles = ChatView.styles;\n\t var button = $(e.currentTarget);\n\t var scrollToLeft = button.find(DOT + viewStyles.scrollButtonIconLeft).length !== 0;\n\t var scrollContainer = button.siblings(DOT + viewStyles.cardDeck);\n\t var lastCard = scrollContainer.find(DOT + viewStyles.card).last();\n\t var cardWidth = lastCard.outerWidth(true);\n\n\t if (scrollToLeft) {\n\t scrollContainer.scrollLeft(scrollContainer.scrollLeft() - cardWidth);\n\t } else {\n\t scrollContainer.scrollLeft(scrollContainer.scrollLeft() + cardWidth);\n\t }\n\t },\n\n\t getTemplate: function(templateName) {\n\t return kendo.chat.getTemplate(templateName);\n\t },\n\n\t getComponent: function(type) {\n\t return kendo.chat.getComponent(type);\n\t },\n\n\t renderMessage: function(message, sender) {\n\t if (!message.timestamp) {\n\t message.timestamp = new Date();\n\t }\n\n\t if (!message.text) {\n\t message.text = \"\";\n\t }\n\n\t var bubbleElement = this._renderTemplate(message.type, message);\n\n\t this._renderBubble(message.type, bubbleElement, sender);\n\n\t if (message.type == \"typing\") {\n\t if (this.typingParticipants.length > 0) {\n\t this._removeTypingParticipant(sender);\n\t }\n\t } else {\n\t this._lastSender = sender.id;\n\t }\n\t },\n\n\t renderSuggestedActions: function(suggestedActions) {\n\t this._removeSuggestedActions();\n\n\t var element = this._renderTemplate(\"suggestedAction\", { suggestedActions: suggestedActions });\n\n\t this.list.append(element);\n\n\t this._scrollToBottom();\n\t },\n\n\t renderAttachments: function(options) {\n\t var wrapper = this._renderAttachmentWrapper(options.attachmentLayout);\n\t var cardContainer = options.attachmentLayout === \"carousel\" ? wrapper.find(DOT + ChatView.styles.cardDeck) : wrapper;\n\t var attachments = options.attachments;\n\n\t if (!attachments.length) {\n\t return;\n\t }\n\n\t for (var i = 0; i < attachments.length; i++) {\n\t var cardElement = this._renderTemplate(attachments[i].contentType, attachments[i].content);\n\n\t cardContainer.append(cardElement);\n\t }\n\n\t this._removeSuggestedActions();\n\t this._removeTypingIndicator();\n\n\t this.list.append(wrapper);\n\n\t this._lastSender = null;\n\t },\n\n\t renderComponent: function(type) {\n\t var componentType = this.getComponent(type);\n\t var component = new componentType({}, this);\n\n\t this.list.append(component.element);\n\n\t this._scrollToBottom();\n\t },\n\n\t _renderAttachmentWrapper: function(layout) {\n\t var viewStyles = ChatView.styles;\n\t var wrapper = $(\"
\");\n\n\t if (layout === \"carousel\") {\n\t wrapper.addClass(viewStyles.cardDeckScrollWrap);\n\n\t var buttonLeft = this._renderScrollButton(viewStyles.scrollButtonIconLeft);\n\t wrapper.append(buttonLeft);\n\n\t wrapper.append($(\"
\").addClass(viewStyles.cardDeck));\n\n\t var buttonRight = this._renderScrollButton(viewStyles.scrollButtonIconRight);\n\t wrapper.append(buttonRight);\n\t } else {\n\t wrapper.addClass(viewStyles.cardList);\n\t }\n\n\t return wrapper;\n\t },\n\n\t _renderScrollButton: function(directionClass) {\n\t var viewStyles = ChatView.styles;\n\n\t return $(\"