Messagebar
Framework7 comes with special resizable toolbar for usage with Messages
Messagebar Layout
Messagebar layout is pretty simple:
<div class="toolbar messagebar">
<div class="toolbar-inner">
<div class="messagebar-area">
<!-- messagebar attachments -->
<div class="messagebar-attachments">...</div>
<!-- messagebar resizable textarea -->
<textarea class="resizable" placeholder="Message"></textarea>
</div>
<a href="#" class="link">Send</a>
</div>
<!-- messagebar sheet -->
<div class="messagebar-sheet">...</div>
</div>
Where
messagebar-attachments
- block with messagebar attachments. Optionalmessagebar-sheet
- block with messagebar sheet. Optional
Messagebar place is very important, it should be inside of page
and right before page-content
:
<div class="page">
<!-- navbar -->
<div class="navbar">...</div>
<!-- messagebar -->
<div class="toolbar messagebar">...</div>
<!-- page-content/messages-content -->
<div class="page-content messages-content">
... messages
</div>
</div>
Messagebar Sheet Layout
If need additional sheet with, for example, images that we can attach to message then we use extra block designed for this:
<div class="messagebar-sheet">
<!-- selectable sheet image -->
<label class="checkbox messagebar-sheet-image" style="background-image:url(path/to/image1.png)">
<input type="checkbox" />
<i class="icon icon-checkbox"></i>
</label>
<!-- another selectable sheet image -->
<label class="checkbox messagebar-sheet-image" style="background-image:url(path/to/image2.png)">
<input type="checkbox" />
<i class="icon icon-checkbox"></i>
</label>
<!-- some custom sheet item -->
<div class="messagebar-sheet-item">
<!-- any custom content here -->
</div>
</div>
Messagebar Attachments Layout
Messages attachments block is designed to display currently attached message items/images:
<div class="messagebar-attachments">
<!-- image attachment -->
<div class="messagebar-attachment">
<img src="path/to/image1.png" />
</div>
<!-- deletable image attachment -->
<div class="messagebar-attachment">
<img src="path/to/image2.png" />
<!-- attachment delete button -->
<span class="messagebar-attachment-delete"></span>
</div>
</div>
Messagebar App Methods
Now, when we have Messagebar' HTML, we need to initialize it. We need to use related App's method:
app.messagebar.create(parameters) | Initialize Messagebar with parameters
|
app.messagebar.destroy(el) | Destroy Messagebar instance
|
app.messagebar.get(el) | Get Messagebar instance by HTML element
|
Messagebar Parameters
Let's look on list of all available parameters:
Parameter | Type | Default | Description |
---|---|---|---|
el | string HTMLElement | CSS selector or HTML element of messagebar element (div class="messagebar" ) | |
textareaEl | string HTMLElement | CSS selector or HTML element of messagebar textarea element. By default (if not passed) will try to look for textarea inside of messagebar | |
maxHeight | number | null | Max height of textarea when it resized depending on amount of its text |
attachments | array | [] | Array with attachments. For example ['path/to/image1.png', 'path/to/image2.png'] |
resizePage | boolean | true | Disable if you don't want to resize messages page when messagebar textarea size changed |
on | object | Object with events handlers. For example:
| |
Render functions | |||
renderAttachments | function(attachments) | Function to render attachments block. Must return full attachments HTML string | |
renderAttachment | function(attachment) | Function to render single attachment. Must return full attachment HTML string |
Messagebar Methods & Properties
So to create Messagebar we have to call:
var messagebar = app.messagebar.create({ /* parameters */ })
After we initialize Messagebar we have its initialized instance in variable (like messagebar
variable in example above) with helpful methods and properties:
Properties | |
---|---|
messagebar.el | Messagebar HTML element. |
messagebar.$el | Dom7 element with messagebar HTML element. |
messagebar.textareaEl | Messagebar textarea HTML element |
messagebar.$textareaEl | Dom7 element with messagebar textarea HTML element |
messagebar.params | Object with passed initialization parameters |
messagebar.attachments | Array with messagebar attachments |
Methods | |
messagebar.getValue(); | Get messagebar textarea value |
messagebar.setValue(value); | Set messagebar textarea value/text |
messagebar.clear(); | Clear textarea and update/reset its size |
messagebar.focus(); | Focus messagebar textarea |
messagebar.blur(); | Remove focus from messagebar textarea |
messagebar.setPlaceholder(placeholder) | Set/change messagebar placeholder text |
messagebar.resizePage() | Force Messagebar to resize messages page depending on messagebar height/size |
messagebar.attachmentsCreate() | Dynamically create attachments block HTML element |
messagebar.attachmentsShow() | Show attachments block |
messagebar.attachmentsHide() | Hide attachments block |
messagebar.attachmentsToggle() | Toggle attachments block |
messagebar.renderAttachments() | Render attachments block based on attachments data |
messagebar.sheetCreate() | Dynamically create messagebar sheet block HTML element |
messagebar.sheetShow() | Show messagebar sheet |
messagebar.sheetHide() | Hide messagebar sheet |
messagebar.sheetToggle() | Toggle messagebar sheet |
messagebar.destroy(); | Destroy messagebar instance |
Messagebar Events
Messagebar will fire the following DOM events on messagebar element and events on app and messagebar instance:
DOM Events
Event | Target | Description |
---|---|---|
messagebar:change | Messagebar Element<div class="messagebar"> | Event will be triggered after messagebar textarea value changed |
messagebar:focus | Messagebar Element<div class="messagebar"> | Event will be triggered when messagebar textarea gets focus |
messagebar:blur | Messagebar Element<div class="messagebar"> | Event will be triggered when messagebar textarea loses focus |
messagebar:resizepage | Messagebar Element<div class="messagebar"> | Event will be triggered when messagebar resizes messages page |
messagebar:attachmentdelete | Messagebar attachment element<div class="messagebar-attachment"> | Event will be triggered after click on messagebar attachment delete button |
messagebar:attachmentclick | Messagebar attachment element<div class="messagebar-attachment"> | Event will be triggered on messagebar attachment click |
messagebar:beforedestroy | Messagebar Element<div class="messagebar"> | Event will be triggered right before Messagebar instance will be destroyed |
App and Messagebar Instance Events
Messagebar instance emits events on both self instance and app instance. App instance events has same names prefixed with messagebar
.
Event | Target | Arguments | Description |
---|---|---|---|
change | messagebar | (messagebar) | Event will be triggered after messagebar textarea value changed. As an argument event handler receives messagebar instance |
messagebarChange | app | ||
focus | messagebar | (messagebar) | Event will be triggered when messagebar textarea gets focus. As an argument event handler receives messagebar instance |
messagebarFocus | app | ||
blur | messagebar | (messagebar) | Event will be triggered when messagebar textarea loses focus. As an argument event handler receives messagebar instance |
messagebarBlur | app | ||
resizePage | messagebar | (messagebar) | Event will be triggered when messagebar resizes messages page. As an argument event handler receives messagebar instance |
messagebarResizePage | app | ||
attachmentDelete | messagebar | (messagebar, attachmentEl, attachmentIndex) | Event will be triggered after click on messagebar attachment delete button. As an argument event handler receives messagebar instance, clicked attachment HTML element and attachment index number |
messagebarAttachmentDelete | app | ||
attachmentClick | messagebar | (messagebar, attachmentEl, attachmentIndex) | Event will be triggered on messagebar attachment click. As an argument event handler receives messagebar instance, clicked attachment HTML element and attachment index number |
messagebarAttachmentClick | app | ||
beforeDestroy | messagebar | (messagebar) | Event will be triggered right before Messagebar instance will be destroyed |
messagebarBeforeDestroy | app |
Messagebar Auto Initialization
If you don't need to use Messagebar API and your Messagebar is inside of the page and presented in DOM on moment of page initialization then it can be auto initialized with just adding additional messagebar-init
class to messagebar element, and all required parameters can be passed using data-
attributes:
<div class="toolbar messagebar messagebar-init" data-max-height="200">
<div class="toolbar-inner">
<div class="messagebar-area">
<textarea placeholder="Message"></textarea>
</div>
<a href="#" class="link">Send</a>
</div>
</div>
Parameters that used in camelCase, for example maxHeight, in data- attributes should be used in kebab-case as data-max-height
CSS Variables
Below is the list of related CSS variables (CSS custom properties).
Note that commented variables are not specified by default and their values is what they fallback to in this case.
:root {
--f7-messagebar-attachments-height: 155px;
--f7-messagebar-sheet-height: 252px;
--f7-messagebar-sheet-landscape-height: 192px;
/*
--f7-messagebar-inner-padding-left: var(--f7-toolbar-inner-padding-left);
--f7-messagebar-inner-padding-right: var(--f7-toolbar-inner-padding-right);
*/
}
.ios {
--f7-messagebar-height: 44px;
--f7-messagebar-font-size: 17px;
--f7-messagebar-textarea-bg-color: transparent;
/*
--f7-messagebar-link-color: var(--f7-theme-color);
*/
--f7-messagebar-border-color: transparent;
--f7-messagebar-textarea-border-radius: 17px;
--f7-messagebar-textarea-padding: 6px 16px;
--f7-messagebar-textarea-height: 34px;
--f7-messagebar-textarea-font-size: 17px;
--f7-messagebar-textarea-line-height: 20px;
--f7-messagebar-sheet-bg-color: #d1d5da;
--f7-messagebar-sheet-border-color: transparent;
--f7-messagebar-attachment-border-radius: 12px;
--f7-messagebar-attachment-height: 155px;
--f7-messagebar-attachment-landscape-height: 120px;
--f7-messagebar-textarea-placeholder-color: rgba(0, 0, 0, 0.4);
--f7-messagebar-textarea-text-color: #000;
--f7-messagebar-textarea-border: 1px solid #c8c8cd;
--f7-messagebar-attachments-border-color: #c8c8cd;
--f7-messagebar-bg-color: #fff;
--f7-messagebar-bg-color-rgb: 255, 255, 255;
}
.ios .dark,
.ios.dark {
--f7-messagebar-textarea-placeholder-color: rgba(255, 255, 255, 0.4);
--f7-messagebar-textarea-text-color: #fff;
--f7-messagebar-textarea-border: 1px solid var(--f7-bars-border-color);
--f7-messagebar-attachments-border-color: var(--f7-bars-border-color);
--f7-messagebar-bg-color: var(--f7-bars-bg-color);
--f7-messagebar-bg-color-rgb: var(--f7-bars-bg-color-rgb);
}
.md {
--f7-messagebar-height: 64px;
--f7-messagebar-font-size: 16px;
--f7-messagebar-textarea-border-radius: 24px;
--f7-messagebar-textarea-padding: 12px 16px;
--f7-messagebar-textarea-height: 48px;
--f7-messagebar-textarea-font-size: 16px;
--f7-messagebar-textarea-line-height: 22px;
--f7-messagebar-textarea-border: 1px solid transparent;
--f7-messagebar-attachment-border-radius: 12px;
--f7-messagebar-attachment-height: 72px;
--f7-messagebar-attachment-landscape-height: 72px;
--f7-messagebar-border-color: transparent;
--f7-messagebar-attachments-border-color: transparent;
}
.md,
.md .dark,
.md [class*='color-'] {
--f7-messagebar-textarea-placeholder-color: var(--f7-md-on-surface-variant);
--f7-messagebar-textarea-bg-color: var(--f7-md-surface-variant);
--f7-messagebar-bg-color: var(--f7-md-surface);
--f7-messagebar-textarea-text-color: var(--f7-md-on-surface);
--f7-messagebar-sheet-bg-color: var(--f7-md-surface);
--f7-messagebar-sheet-border-color: var(--f7-md-outline-variant);
--f7-messagebar-link-color: var(--f7-md-on-surface);
}
Examples
<template>
<div class="page">
<div class="navbar">
<div class="navbar-bg"></div>
<div class="navbar-inner sliding">
<div class="title">Messages</div>
</div>
</div>
<div class="toolbar messagebar" @messagebar:attachmentdelete=${deleteAttachment}>
<div class="toolbar-inner">
<a class="link icon-only" @click=${sheetToggle}>
<i class="icon f7-icons if-not-md">camera_fill</i>
<i class="icon material-icons md-only">camera_alt</i>
</a>
<div class="messagebar-area">
<textarea class="resizable" placeholder="Message"></textarea>
</div>
<a class="link icon-only demo-send-message-link" @click=${sendMessage}>
<i class="icon f7-icons if-not-md">arrow_up_circle_fill</i>
<i class="icon material-icons md-only">send</i>
</a>
</div>
<div class="messagebar-sheet">
${images.map((image) => $h`
<label class="checkbox messagebar-sheet-image" @change=${handleAttachment}>
<input type="checkbox" />
<i class="icon icon-checkbox"></i>
<img src=${image} />
</label>
`)}
</div>
</div>
<div class="page-content messages-content">
<div class="messages">
<div class="messages-title"><b>Sunday, Feb 9,</b> 12:58</div>
<div class="message message-sent">
<div class="message-content">
<div class="message-bubble">
<div class="message-text">Hi, Kate</div>
</div>
</div>
</div>
<div class="message message-sent">
<div class="message-content">
<div class="message-bubble">
<div class="message-text">How are you?</div>
</div>
</div>
</div>
<div class="message message-received">
<div class="message-avatar"
style="background-image:url(https://cdn.framework7.io/placeholder/people-100x100-9.jpg)"></div>
<div class="message-content">
<div class="message-name">Kate</div>
<div class="message-bubble">
<div class="message-text">Hi, I am good!</div>
</div>
</div>
</div>
<div class="message message-received">
<div class="message-avatar"
style="background-image:url(https://cdn.framework7.io/placeholder/people-100x100-7.jpg)"></div>
<div class="message-content">
<div class="message-name">Blue Ninja</div>
<div class="message-bubble">
<div class="message-text">Hi there, I am also fine, thanks! And how are you?</div>
</div>
</div>
</div>
<div class="message message-sent">
<div class="message-content">
<div class="message-bubble">
<div class="message-text">Hey, Blue Ninja! Glad to see you ;)</div>
</div>
</div>
</div>
<div class="message message-sent">
<div class="message-content">
<div class="message-bubble">
<div class="message-text">Hey, look, cutest kitten ever!</div>
</div>
</div>
</div>
<div class="message message-sent">
<div class="message-content">
<div class="message-bubble">
<div class="message-image">
<img src="https://cdn.framework7.io/placeholder/cats-200x260-4.jpg"
style="width:200px; height: 260px" />
</div>
</div>
</div>
</div>
<div class="message message-received">
<div class="message-avatar"
style="background-image:url(https://cdn.framework7.io/placeholder/people-100x100-9.jpg)"></div>
<div class="message-content">
<div class="message-name">Kate</div>
<div class="message-bubble">
<div class="message-text">Nice!</div>
</div>
</div>
</div>
<div class="message message-received">
<div class="message-avatar"
style="background-image:url(https://cdn.framework7.io/placeholder/people-100x100-9.jpg)"></div>
<div class="message-content">
<div class="message-name">Kate</div>
<div class="message-bubble">
<div class="message-text">Like it very much!</div>
</div>
</div>
</div>
<div class="message message-received">
<div class="message-avatar"
style="background-image:url(https://cdn.framework7.io/placeholder/people-100x100-7.jpg)"></div>
<div class="message-content">
<div class="message-name">Blue Ninja</div>
<div class="message-bubble">
<div class="message-text">Awesome!</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default (props, { $f7, $el, $on, $ }) => {
const images = [
'https://cdn.framework7.io/placeholder/cats-300x300-1.jpg',
'https://cdn.framework7.io/placeholder/cats-200x300-2.jpg',
'https://cdn.framework7.io/placeholder/cats-400x300-3.jpg',
'https://cdn.framework7.io/placeholder/cats-300x150-4.jpg',
'https://cdn.framework7.io/placeholder/cats-150x300-5.jpg',
'https://cdn.framework7.io/placeholder/cats-300x300-6.jpg',
'https://cdn.framework7.io/placeholder/cats-300x300-7.jpg',
'https://cdn.framework7.io/placeholder/cats-200x300-8.jpg',
'https://cdn.framework7.io/placeholder/cats-400x300-9.jpg',
'https://cdn.framework7.io/placeholder/cats-300x150-10.jpg'
];
const people = [
{
name: 'Kate Johnson',
avatar: 'https://cdn.framework7.io/placeholder/people-100x100-9.jpg'
},
{
name: 'Blue Ninja',
avatar: 'https://cdn.framework7.io/placeholder/people-100x100-7.jpg'
},
];
const answers = [
'Yes!',
'No',
'Hm...',
'I am not sure',
'And what about you?',
'May be ;)',
'Lorem ipsum dolor sit amet, consectetur',
'What?',
'Are you sure?',
'Of course',
'Need to think about it',
'Amazing!!!',
];
let responseInProgress = false;
let messagebar;
let messages;
const sheetToggle = () => {
messagebar.sheetToggle();
}
const deleteAttachment = (e, index) => {
var image = messagebar.attachments.splice(index, 1)[0];
messagebar.renderAttachments();
checkAttachments();
// Uncheck in sheet
var imageIndex = images.indexOf(image);
$el.value.find('.messagebar-sheet .checkbox').eq(imageIndex).find('input').prop('checked', false);
}
const handleAttachment = (e) => {
var index = $(e.target).parents('label.checkbox').index();
var image = images[index];
if (e.target.checked) {
// Add to attachments
messagebar.attachments.unshift(image)
} else {
// Remove from attachments
messagebar.attachments.splice(messagebar.attachments.indexOf(image), 1);
}
messagebar.renderAttachments();
checkAttachments();
}
const checkAttachments = () => {
if (messagebar.attachments.length > 0) {
messagebar.attachmentsShow();
messagebar.setPlaceholder('Add comment or Send');
} else {
messagebar.attachmentsHide();
messagebar.setPlaceholder('Message');
}
}
const sendMessage = () => {
var text = messagebar.getValue().replace(/\n/g, '<br />').trim();
var messagesToSend = [];
messagebar.attachments.forEach(function (attachment) {
var size = attachment.split('placeholder/cats-')[1].split('-')[0].split('x');
messagesToSend.push({
image: '<img src="' + attachment + '" style="width: ' + (size[0] / 2) + 'px; height: ' + (size[1] / 2) + 'px">'
});
});
if (text.trim().length) {
messagesToSend.push({
text: text
});
}
// Reset attachments
messagebar.attachments = [];
checkAttachments();
// Hide sheet
messagebar.sheetHide();
// Uncheck selected images in sheet
messagebar.$sheetEl.find('input').prop('checked', false);
// Clear area
messagebar.clear();
// Focus area
if (text.length) messagebar.focus();
// Exit when nothing to send
if (!messagesToSend.length) return;
// Send message
messages.addMessages(messagesToSend);
// Mock response
if (responseInProgress) return;
responseInProgress = true;
setTimeout(function () {
var answer = answers[Math.floor(Math.random() * answers.length)];
var person = people[Math.floor(Math.random() * people.length)];
messages.showTyping({
header: person.name + ' is typing',
avatar: person.avatar
});
setTimeout(function () {
messages.addMessage({
text: answer,
type: 'received',
name: person.name,
avatar: person.avatar
});
messages.hideTyping();
responseInProgress = false;
}, 4000);
}, 1000);
}
$on('pageInit', () => {
messagebar = $f7.messagebar.create({
el: $el.value.find('.messagebar'),
attachments: []
});
messages = $f7.messages.create({
el: $el.value.find('.messages'),
firstMessageRule: function (message, previousMessage, nextMessage) {
if (message.isTitle) return false;
if (!previousMessage || previousMessage.type !== message.type || previousMessage.name !== message.name) return true;
return false;
},
lastMessageRule: function (message, previousMessage, nextMessage) {
if (message.isTitle) return false;
if (!nextMessage || nextMessage.type !== message.type || nextMessage.name !== message.name) return true;
return false;
},
tailMessageRule: function (message, previousMessage, nextMessage) {
if (message.isTitle) return false;
if (!nextMessage || nextMessage.type !== message.type || nextMessage.name !== message.name) return true;
return false;
}
});
})
$on('pageBeforeRemove', () => {
messagebar.destroy()
messages.destroy()
})
return $render;
};
</script>