web-apps/vendor/framework7/src/js/smart-select.js
2016-11-11 16:24:21 +03:00

520 lines
22 KiB
JavaScript

/*===============================================================================
************ Smart Select ************
===============================================================================*/
app.initSmartSelects = function (pageContainer) {
pageContainer = $(pageContainer);
var selects;
if (pageContainer.is('.smart-select')) {
selects = pageContainer;
}
else {
selects = pageContainer.find('.smart-select');
}
if (selects.length === 0) return;
selects.each(function () {
var smartSelect = $(this);
var $select = smartSelect.find('select');
if ($select.length === 0) return;
var select = $select[0];
if (select.length === 0) return;
var valueText = [];
for (var i = 0; i < select.length; i++) {
if (select[i].selected) valueText.push(select[i].textContent.trim());
}
var itemAfter = smartSelect.find('.item-after');
if (itemAfter.length === 0) {
smartSelect.find('.item-inner').append('<div class="item-after">' + valueText.join(', ') + '</div>');
}
else {
var selectedText = itemAfter.text();
if (itemAfter.hasClass('smart-select-value')) {
for (i = 0; i < select.length; i++) {
select[i].selected = select[i].textContent.trim() === selectedText.trim();
}
} else {
itemAfter.text(valueText.join(', '));
}
}
$select.on('change', function () {
var valueText = [];
for (var i = 0; i < select.length; i++) {
if (select[i].selected) valueText.push(select[i].textContent.trim());
}
smartSelect.find('.item-after').text(valueText.join(', '));
});
});
};
app.smartSelectAddOption = function (select, option, index) {
select = $(select);
var smartSelect = select.parents('.smart-select');
if (typeof index === 'undefined') {
select.append(option);
}
else {
$(option).insertBefore(select.find('option').eq(index));
}
app.initSmartSelects(smartSelect);
var selectName = smartSelect.find('select').attr('name');
var opened = $('.page.smart-select-page[data-select-name="' + selectName + '"]').length > 0;
if (opened) {
app.smartSelectOpen(smartSelect, true);
}
};
app.smartSelectOpen = function (smartSelect, reLayout) {
smartSelect = $(smartSelect);
if (smartSelect.length === 0) return;
// Find related view
var view = smartSelect.parents('.' + app.params.viewClass);
if (view.length === 0) return;
view = view[0].f7View;
// Parameters
var openIn = smartSelect.attr('data-open-in') || app.params.smartSelectOpenIn;
if (openIn === 'popup') {
if ($('.popup.smart-select-popup').length > 0) return;
}
else if (openIn === 'picker') {
if ($('.picker-modal.modal-in').length > 0 && !reLayout){
if (smartSelect[0].f7SmartSelectPicker !== $('.picker-modal.modal-in:not(.modal-out)')[0]) app.closeModal($('.picker-modal.modal-in:not(.modal-out)'));
else return;
}
}
else {
if (!view) return;
}
var smartSelectData = smartSelect.dataset();
var pageTitle = smartSelectData.pageTitle || smartSelect.find('.item-title').text();
var backText = smartSelectData.backText || app.params.smartSelectBackText;
var closeText;
if (openIn === 'picker') {
closeText = smartSelectData.pickerCloseText || smartSelectData.backText || app.params.smartSelectPickerCloseText ;
}
else {
closeText = smartSelectData.popupCloseText || smartSelectData.backText || app.params.smartSelectPopupCloseText ;
}
var backOnSelect = smartSelectData.backOnSelect !== undefined ? smartSelectData.backOnSelect : app.params.smartSelectBackOnSelect;
var formTheme = smartSelectData.formTheme || app.params.smartSelectFormTheme;
var navbarTheme = smartSelectData.navbarTheme || app.params.smartSelectNavbarTheme;
var toolbarTheme = smartSelectData.toolbarTheme || app.params.smartSelectToolbarTheme;
var virtualList = smartSelectData.virtualList;
var virtualListHeight = smartSelectData.virtualListHeight;
var material = app.params.material;
var pickerHeight = smartSelectData.pickerHeight || app.params.smartSelectPickerHeight;
// Collect all options/values
var select = smartSelect.find('select')[0];
var $select = $(select);
var $selectData = $select.dataset();
if (select.disabled || smartSelect.hasClass('disabled') || $select.hasClass('disabled')) {
return;
}
var values = [];
var id = (new Date()).getTime();
var inputType = select.multiple ? 'checkbox' : 'radio';
var inputName = inputType + '-' + id;
var maxLength = $select.attr('maxlength');
var selectName = select.name;
var option, optionHasMedia, optionImage, optionIcon, optionGroup, optionGroupLabel, optionPreviousGroup, optionIsLabel, previousGroup, optionColor, optionClassName, optionData;
for (var i = 0; i < select.length; i++) {
option = $(select[i]);
optionData = option.dataset();
optionImage = optionData.optionImage || $selectData.optionImage || smartSelectData.optionImage;
optionIcon = optionData.optionIcon || $selectData.optionIcon || smartSelectData.optionIcon;
optionHasMedia = optionImage || optionIcon || inputType === 'checkbox';
if (material) optionHasMedia = optionImage || optionIcon;
optionColor = optionData.optionColor;
optionClassName = optionData.optionClass;
if (option[0].disabled) optionClassName += ' disabled';
optionGroup = option.parent('optgroup')[0];
optionGroupLabel = optionGroup && optionGroup.label;
optionIsLabel = false;
if (optionGroup) {
if (optionGroup !== previousGroup) {
optionIsLabel = true;
previousGroup = optionGroup;
values.push({
groupLabel: optionGroupLabel,
isLabel: optionIsLabel
});
}
}
values.push({
value: option[0].value,
text: option[0].textContent.trim(),
selected: option[0].selected,
group: optionGroup,
groupLabel: optionGroupLabel,
image: optionImage,
icon: optionIcon,
color: optionColor,
className: optionClassName,
disabled: option[0].disabled,
inputType: inputType,
id: id,
hasMedia: optionHasMedia,
checkbox: inputType === 'checkbox',
inputName: inputName,
material: app.params.material
});
}
// Item template/HTML
if (!app._compiledTemplates.smartSelectItem) {
app._compiledTemplates.smartSelectItem = t7.compile(app.params.smartSelectItemTemplate ||
'{{#if isLabel}}' +
'<li class="item-divider">{{groupLabel}}</li>' +
'{{else}}' +
'<li{{#if className}} class="{{className}}"{{/if}}>' +
'<label class="label-{{inputType}} item-content">' +
'<input type="{{inputType}}" name="{{inputName}}" value="{{value}}" {{#if selected}}checked{{/if}}>' +
'{{#if material}}' +
'{{#if hasMedia}}' +
'<div class="item-media">' +
'{{#if icon}}<i class="icon {{icon}}"></i>{{/if}}' +
'{{#if image}}<img src="{{image}}">{{/if}}' +
'</div>' +
'<div class="item-inner">' +
'<div class="item-title{{#if color}} color-{{color}}{{/if}}">{{text}}</div>' +
'</div>' +
'<div class="item-after">' +
'<i class="icon icon-form-{{inputType}}"></i>' +
'</div>' +
'{{else}}' +
'<div class="item-media">' +
'<i class="icon icon-form-{{inputType}}"></i>' +
'</div>' +
'<div class="item-inner">' +
'<div class="item-title{{#if color}} color-{{color}}{{/if}}">{{text}}</div>' +
'</div>' +
'{{/if}}' +
'{{else}}' +
'{{#if hasMedia}}' +
'<div class="item-media">' +
'{{#if checkbox}}<i class="icon icon-form-checkbox"></i>{{/if}}' +
'{{#if icon}}<i class="icon {{icon}}"></i>{{/if}}' +
'{{#if image}}<img src="{{image}}">{{/if}}' +
'</div>' +
'{{/if}}' +
'<div class="item-inner">' +
'<div class="item-title{{#if color}} color-{{color}}{{/if}}">{{text}}</div>' +
'</div>' +
'{{/if}}' +
'</label>' +
'</li>' +
'{{/if}}'
);
}
var smartSelectItemTemplate = app._compiledTemplates.smartSelectItem;
var inputsHTML = '';
if (!virtualList) {
for (var j = 0; j < values.length; j++) {
inputsHTML += smartSelectItemTemplate(values[j]);
}
}
// Toolbar / Navbar
var toolbarHTML = '', navbarHTML;
var noNavbar = '', noToolbar = '', noTabbar = '', navbarLayout;
if (openIn === 'picker') {
if (!app._compiledTemplates.smartSelectToolbar) {
app._compiledTemplates.smartSelectToolbar = t7.compile(app.params.smartSelectToolbarTemplate ||
'<div class="toolbar {{#if toolbarTheme}}theme-{{toolbarTheme}}{{/if}}">' +
'<div class="toolbar-inner">' +
'<div class="left"></div>' +
'<div class="right"><a href="#" class="link close-picker"><span>{{closeText}}</span></a></div>' +
'</div>' +
'</div>'
);
}
toolbarHTML = app._compiledTemplates.smartSelectToolbar({
pageTitle: pageTitle,
closeText: closeText,
openIn: openIn,
toolbarTheme: toolbarTheme,
inPicker: openIn === 'picker'
});
}
else {
// Navbar HTML
if (!app._compiledTemplates.smartSelectNavbar) {
app._compiledTemplates.smartSelectNavbar = t7.compile(app.params.smartSelectNavbarTemplate ||
'<div class="navbar {{#if navbarTheme}}theme-{{navbarTheme}}{{/if}}">' +
'<div class="navbar-inner">' +
'{{leftTemplate}}' +
'<div class="center sliding">{{pageTitle}}</div>' +
'</div>' +
'</div>'
);
}
navbarHTML = app._compiledTemplates.smartSelectNavbar({
pageTitle: pageTitle,
backText: backText,
closeText: closeText,
openIn: openIn,
navbarTheme: navbarTheme,
inPopup: openIn === 'popup',
inPage: openIn === 'page',
leftTemplate: openIn === 'popup' ?
(app.params.smartSelectPopupCloseTemplate || (material ? '<div class="left"><a href="#" class="link close-popup icon-only"><i class="icon icon-back"></i></a></div>' : '<div class="left"><a href="#" class="link close-popup"><i class="icon icon-back"></i><span>{{closeText}}</span></a></div>')).replace(/{{closeText}}/g, closeText) :
(app.params.smartSelectBackTemplate || (material ? '<div class="left"><a href="#" class="back link icon-only"><i class="icon icon-back"></i></a></div>' : '<div class="left sliding"><a href="#" class="back link"><i class="icon icon-back"></i><span>{{backText}}</span></a></div>')).replace(/{{backText}}/g, backText)
});
// Determine navbar layout type - static/fixed/through
if (openIn === 'page') {
navbarLayout = 'static';
if (smartSelect.parents('.navbar-through').length > 0) navbarLayout = 'through';
if (smartSelect.parents('.navbar-fixed').length > 0) navbarLayout = 'fixed';
noToolbar = smartSelect.parents('.page').hasClass('no-toolbar') ? 'no-toolbar' : '';
noNavbar = smartSelect.parents('.page').hasClass('no-navbar') ? 'no-navbar' : 'navbar-' + navbarLayout;
noTabbar = smartSelect.parents('.page').hasClass('no-tabbar') ? 'no-tabbar' : '';
}
else {
navbarLayout = 'fixed';
}
}
// Page Layout
var pageName = 'smart-select-' + inputName;
var useSearchbar = typeof smartSelect.data('searchbar') === 'undefined' ? app.params.smartSelectSearchbar : (smartSelect.data('searchbar') === 'true' ? true : false);
var searchbarPlaceholder, searchbarCancel;
if (useSearchbar) {
searchbarPlaceholder = smartSelect.data('searchbar-placeholder') || 'Search';
searchbarCancel = smartSelect.data('searchbar-cancel') || 'Cancel';
}
var searchbarHTML = '<form class="searchbar searchbar-init" data-search-list=".smart-select-list-' + id + '" data-search-in=".item-title">' +
'<div class="searchbar-input">' +
'<input type="search" placeholder="' + searchbarPlaceholder + '">' +
'<a href="#" class="searchbar-clear"></a>' +
'</div>' +
(material ? '' : '<a href="#" class="searchbar-cancel">' + searchbarCancel + '</a>') +
'</form>' +
'<div class="searchbar-overlay"></div>';
var pageHTML =
(openIn !== 'picker' && navbarLayout === 'through' ? navbarHTML : '') +
'<div class="pages">' +
' <div data-page="' + pageName + '" data-select-name="' + selectName + '" class="page smart-select-page ' + noNavbar + ' ' + noToolbar + ' ' + noTabbar + '">' +
(openIn !== 'picker' && navbarLayout === 'fixed' ? navbarHTML : '') +
(useSearchbar ? searchbarHTML : '') +
' <div class="page-content">' +
(openIn !== 'picker' && navbarLayout === 'static' ? navbarHTML : '') +
' <div class="list-block ' + (virtualList ? 'virtual-list' : '') + ' smart-select-list-' + id + ' ' + (formTheme ? 'theme-' + formTheme : '') + '">' +
' <ul>' +
(virtualList ? '' : inputsHTML) +
' </ul>' +
' </div>' +
' </div>' +
' </div>' +
'</div>';
// Define popup and picker
var popup, picker;
// Scroll SS Picker To Input
function scrollToInput() {
var pageContent = smartSelect.parents('.page-content');
if (pageContent.length === 0) return;
var paddingTop = parseInt(pageContent.css('padding-top'), 10),
paddingBottom = parseInt(pageContent.css('padding-bottom'), 10),
pageHeight = pageContent[0].offsetHeight - paddingTop - picker.height(),
pageScrollHeight = pageContent[0].scrollHeight - paddingTop - picker.height(),
newPaddingBottom;
var inputTop = smartSelect.offset().top - paddingTop + smartSelect[0].offsetHeight;
if (inputTop > pageHeight) {
var scrollTop = pageContent.scrollTop() + inputTop - pageHeight;
if (scrollTop + pageHeight > pageScrollHeight) {
newPaddingBottom = scrollTop + pageHeight - pageScrollHeight + paddingBottom;
if (pageHeight === pageScrollHeight) {
newPaddingBottom = picker.height();
}
pageContent.css({'padding-bottom': (newPaddingBottom) + 'px'});
}
pageContent.scrollTop(scrollTop, 300);
}
}
// Close SS Picker on HTML Click
function closeOnHTMLClick(e) {
var close = true;
if (e.target === smartSelect[0] || $(e.target).parents(smartSelect[0]).length > 0) {
close = false;
}
if ($(e.target).parents('.picker-modal').length > 0) {
close = false;
}
if (close) {
app.closeModal('.smart-select-picker.modal-in');
}
}
// Check max length
function checkMaxLength(container) {
if (select.selectedOptions.length >= maxLength) {
container.find('input[type="checkbox"]').each(function () {
if (!this.checked) {
$(this).parents('li').addClass('disabled');
}
else {
$(this).parents('li').removeClass('disabled');
}
});
}
else {
container.find('.disabled').removeClass('disabled');
}
}
// Event Listeners on new page
function handleInputs(container) {
container = $(container);
if (virtualList) {
var virtualListInstance = app.virtualList(container.find('.virtual-list'), {
items: values,
template: smartSelectItemTemplate,
height: virtualListHeight || undefined,
searchByItem: function (query, index, item) {
if (item.text.toLowerCase().indexOf(query.trim().toLowerCase()) >=0 ) return true;
return false;
}
});
container.once(openIn === 'popup' || openIn === 'picker' ? 'closed': 'pageBeforeRemove', function () {
if (virtualListInstance && virtualListInstance.destroy) virtualListInstance.destroy();
});
}
if (maxLength) {
checkMaxLength(container);
}
if (backOnSelect) {
container.find('input[type="radio"][name="' + inputName + '"]:checked').parents('label').once('click', function () {
if (openIn === 'popup') app.closeModal(popup);
else if (openIn === 'picker') app.closeModal(picker);
else view.router.back();
});
}
container.on('change', 'input[name="' + inputName + '"]', function () {
var input = this;
var value = input.value;
var optionText = [];
if (input.type === 'checkbox') {
var values = [];
for (var i = 0; i < select.options.length; i++) {
var option = select.options[i];
if (option.value === value) {
option.selected = input.checked;
}
if (option.selected) {
optionText.push(option.textContent.trim());
}
}
if (maxLength) {
checkMaxLength(container);
}
}
else {
optionText = [smartSelect.find('option[value="' + value + '"]').text()];
select.value = value;
}
$select.trigger('change');
smartSelect.find('.item-after').text(optionText.join(', '));
if (backOnSelect && inputType === 'radio') {
if (openIn === 'popup') app.closeModal(popup);
else if (openIn === 'picker') app.closeModal(picker);
else view.router.back();
}
});
}
function pageInit(e) {
var page = e.detail.page;
if (page.name === pageName) {
handleInputs(page.container);
}
}
if (openIn === 'popup') {
if (reLayout) {
popup = $('.popup.smart-select-popup .view');
popup.html(pageHTML);
}
else {
popup = app.popup(
'<div class="popup smart-select-popup smart-select-popup-' + inputName + '">' +
'<div class="view navbar-fixed">' +
pageHTML +
'</div>' +
'</div>'
);
popup = $(popup);
}
app.initPage(popup.find('.page'));
handleInputs(popup);
}
else if (openIn === 'picker') {
if (reLayout) {
picker = $('.picker-modal.smart-select-picker .view');
picker.html(pageHTML);
}
else {
picker = app.pickerModal(
'<div class="picker-modal smart-select-picker smart-select-picker-' + inputName + '"' + (pickerHeight ? ' style="height:' + pickerHeight + '"' : '') + '>' +
toolbarHTML +
'<div class="picker-modal-inner">' +
'<div class="view">' +
pageHTML +
'</div>' +
'</div>' +
'</div>'
);
picker = $(picker);
// Scroll To Input
scrollToInput();
// Close On Click
$('html').on('click', closeOnHTMLClick);
// On Close
picker.once('close', function () {
// Reset linked picker
smartSelect[0].f7SmartSelectPicker = undefined;
// Detach html click
$('html').off('click', closeOnHTMLClick);
// Restore page padding bottom
smartSelect.parents('.page-content').css({paddingBottom: ''});
});
// Link Picker
smartSelect[0].f7SmartSelectPicker = picker[0];
}
// Init Page
app.initPage(picker.find('.page'));
// Attach events
handleInputs(picker);
}
else {
$(document).once('pageInit', '.smart-select-page', pageInit);
view.router.load({
content: pageHTML,
reload: reLayout ? true : undefined
});
}
};