/*=============================================================================== ************ Autocomplete ************ ===============================================================================*/ var Autocomplete = function (params) { var a = this; // Params var defaults = { // Standalone Options /* opener: undefined, */ popupCloseText: 'Close', backText: 'Back', searchbarPlaceholderText: 'Search...', searchbarCancelText: 'Cancel', openIn: 'page', backOnSelect: false, notFoundText: 'Nothing found', /* pageTitle: undefined, */ // Handle Data /* source: undefined, limit: undefined, */ valueProperty: 'id', textProperty: 'text', // Dropdown Options /* dropdownPlaceholderText: 'Type anything...', */ updateInputValueOnSelect: true, expandInput: false, // Preloader preloaderColor: false, preloader: false, // Templates /* itemTemplate: undefined, navbarTemplate: undefined, dropdownTemplate: undefined dropdownItemTemplate: undefined, dropdownPlaceholderTemplate: undefined */ // Color themes /* navbarTheme: undefined, formTheme: undefined, */ // Callbacks /* onChange: function (a, value) - for not dropdown onOpen: function (a) onClose: function (a) */ }; params = params || {}; for (var def in defaults) { if (typeof params[def] === 'undefined') { params[def] = defaults[def]; } } a.params = params; // Opener Link & View if (a.params.opener) { a.opener = $(a.params.opener); } var view = a.params.view; if (!a.params.view && a.opener && a.opener.length) { // Find related view view = a.opener.parents('.' + app.params.viewClass); if (view.length === 0) return; view = view[0].f7View; } // Input if (a.params.input) { a.input = $(a.params.input); if (a.input.length === 0 && a.params.openIn === 'dropdown') return; } // Array with selected items a.value = a.params.value || []; // ID & Inputs a.id = (new Date()).getTime(); a.inputType = a.params.multiple ? 'checkbox' : 'radio'; a.inputName = a.inputType + '-' + a.id; // Is Material var material = app.params.material; // Back On Select var backOnSelect = a.params.backOnSelect; if (a.params.openIn !== 'dropdown') { // Item Template a.itemTemplate = t7.compile(a.params.itemTemplate || '
  • ' + '' + '
  • ' ); // Page Layout var pageTitle = a.params.pageTitle || ''; if (!pageTitle && a.opener && a.opener.length) { pageTitle = a.opener.find('.item-title').text(); } var pageName = 'autocomplete-' + a.inputName; var navbarTheme = a.params.navbarTheme, formTheme = a.params.formTheme; // Navbar HTML var navbarHTML; var noNavbar = '', noToolbar = '', navbarLayout; a.navbarTemplate = t7.compile(a.params.navbarTemplate || '' ); navbarHTML = a.navbarTemplate({ pageTitle: pageTitle, backText: a.params.backText, popupCloseText: a.params.popupCloseText, openIn: a.params.openIn, navbarTheme: navbarTheme, inPopup: a.params.openIn === 'popup', inPage: a.params.openIn === 'page', material: material, preloader: a.params.preloader, preloaderColor: a.params.preloaderColor, }); // Determine navbar layout type - static/fixed/through if (a.params.openIn === 'page') { navbarLayout = 'static'; if (a.opener) { if (a.opener.parents('.navbar-through').length > 0) navbarLayout = 'through'; if (a.opener.parents('.navbar-fixed').length > 0) navbarLayout = 'fixed'; noToolbar = a.opener.parents('.page').hasClass('no-toolbar') ? 'no-toolbar' : ''; noNavbar = a.opener.parents('.page').hasClass('no-navbar') ? 'no-navbar' : 'navbar-' + navbarLayout; } else if (view.container) { if ($(view.container).hasClass('navbar-through') || $(view.container).find('.navbar-through').length > 0) navbarLayout = 'through'; if ($(view.container).hasClass('navbar-fixed') || $(view.container).find('.navbar-fixed').length > 0) navbarLayout = 'fixed'; noToolbar = $(view.activePage.container).hasClass('no-toolbar') ? 'no-toolbar' : ''; noNavbar = $(view.activePage.container).hasClass('no-navbar') ? 'no-navbar' : 'navbar-' + navbarLayout; } } else { navbarLayout = 'fixed'; } var searchbarHTML = '' + '
    '; var pageHTML = (navbarLayout === 'through' ? navbarHTML : '') + '
    ' + '
    ' + (navbarLayout === 'fixed' ? navbarHTML : '') + searchbarHTML + '
    ' + (navbarLayout === 'static' ? navbarHTML : '') + '
    ' + '
      ' + '
      ' + '
      ' + '
      • ' + a.params.notFoundText + '
      ' + '
      ' + '
      ' + '
        ' + '
        ' + '
        ' + '
        ' + '
        '; } else { a.dropdownItemTemplate = t7.compile(a.params.dropdownItemTemplate || '
      • ' + '' + '
      • ' ); a.dropdownPlaceholderTemplate = t7.compile(a.params.dropdownPlaceholderTemplate || '
      • ' + '
        ' + '
        ' + '
        {{text}}
        ' + '
        ' + '' + '
      • ' ); a.dropdownTemplate = t7.compile(a.params.dropdownTemplate || '
        ' + '
        ' + '
        ' + '
          ' + '
          ' + '
          ' + '{{#if preloader}}' + '
          {{#if material}}{{materialPreloaderHtml}}{{/if}}
          ' + '{{/if}}' + '
          ' ); } // Define popup a.popup = undefined; // Define Dropdown a.dropdown = undefined; // Handle Input Value Change function handleInputValue (e) { var query = a.input.val(); if (a.params.source) { a.params.source(a, query, function (items) { var itemsHTML = ''; var limit = a.params.limit ? Math.min(a.params.limit, items.length) : items.length; a.items = items; var i, j; var regExp = new RegExp('('+query+')', 'i'); for (i = 0; i < limit; i++) { var itemValue = typeof items[i] === 'object' ? items[i][a.params.valueProperty] : items[i]; itemsHTML += a.dropdownItemTemplate({ value: itemValue, text: (typeof items[i] !== 'object' ? items[i] : items[i][a.params.textProperty]).replace(regExp, '$1') }); } if (itemsHTML === '' && query === '' && a.params.dropdownPlaceholderText) { itemsHTML += a.dropdownPlaceholderTemplate({ text: a.params.dropdownPlaceholderText, }); } a.dropdown.find('ul').html(itemsHTML); }); } } // Handle Drop Down Click function handleDropdownClick (e) { /*jshint validthis:true */ var clicked = $(this); var clickedItem; for (var i = 0; i < a.items.length; i++) { var itemValue = typeof a.items[i] === 'object' ? a.items[i][a.params.valueProperty] : a.items[i]; var value = clicked.attr('data-value'); if (itemValue === value || itemValue * 1 === value * 1) { clickedItem = a.items[i]; } } if (a.params.updateInputValueOnSelect) { a.input.val(typeof clickedItem === 'object' ? clickedItem[a.params.textProperty] : clickedItem); a.input.trigger('input change'); } if (a.params.onChange) { a.params.onChange(a, clickedItem); } a.close(); } // Handle HTML Click to close Dropdown function closeOnHTMLClick (e) { var target = $(e.target); if (!(target.is(a.input[0]) || a.dropdown && target.parents(a.dropdown[0]).length > 0)) { a.close(); } } a.positionDropDown = function () { var listBlock = a.input.parents('.list-block'), pageContent = a.input.parents('.page-content'), paddingTop = parseInt(pageContent.css('padding-top'), 10), paddingBottom = parseInt(pageContent.css('padding-top'), 10), // inputOffset = a.input.offset(), listBlockOffsetLeft = listBlock.length > 0 ? listBlock.offset().left - listBlock.parent().offset().left : 0, inputOffsetLeft = a.input.offset().left - (listBlock.length > 0 ? listBlock.offset().left : 0), inputOffsetTop = a.input.offset().top - (pageContent.offset().top - pageContent[0].scrollTop), maxHeight = pageContent[0].scrollHeight - paddingBottom - (inputOffsetTop + pageContent[0].scrollTop) - a.input[0].offsetHeight; a.dropdown.css({ left: (listBlock.length > 0 ? listBlockOffsetLeft : inputOffsetLeft) + 'px', top: inputOffsetTop + pageContent[0].scrollTop + a.input[0].offsetHeight + 'px', width: (listBlock.length > 0 ? listBlock[0].offsetWidth : a.input[0].offsetWidth) + 'px' }); a.dropdown.children('.autocomplete-dropdown-inner').css({ maxHeight: maxHeight + 'px', paddingLeft: listBlock.length > 0 && !a.params.expandInput ? inputOffsetLeft - (material ? 16 : 15) + 'px' : '' }); }; // Event Listeners on new page a.pageInit = function (e) { var page = e.detail.page; a.page = $(page.container); a.pageData = page; if (page.name !== pageName) { return; } var container = $(page.container); // Init Search Bar var searchbar = app.searchbar(container.find('.searchbar'), { customSearch: true, onSearch: function (searchbar, data) { if (data.query.length === 0 && searchbar.active) { searchbar.overlay.addClass('searchbar-overlay-active'); } else { searchbar.overlay.removeClass('searchbar-overlay-active'); } var i, j, k; if (a.params.source) { a.params.source(a, data.query, function(items) { var itemsHTML = ''; var limit = a.params.limit ? Math.min(a.params.limit, items.length) : items.length; a.items = items; for (i = 0; i < limit; i++) { var selected = false; var itemValue = typeof items[i] === 'object' ? items[i][a.params.valueProperty] : items[i]; for (j = 0; j < a.value.length; j++) { var aValue = typeof a.value[j] === 'object' ? a.value[j][a.params.valueProperty] : a.value[j]; if (aValue === itemValue || aValue * 1 === itemValue * 1) selected = true; } itemsHTML += a.itemTemplate({ value: itemValue, text: typeof items[i] !== 'object' ? items[i] : items[i][a.params.textProperty], inputType: a.inputType, id: a.id, inputName: a.inputName, selected: selected, checkbox: a.inputType === 'checkbox', material: material }); } container.find('.autocomplete-found ul').html(itemsHTML); if (items.length === 0) { if (data.query.length !== 0) { container.find('.autocomplete-not-found').show(); container.find('.autocomplete-found, .autocomplete-values').hide(); } else { container.find('.autocomplete-values').show(); container.find('.autocomplete-found, .autocomplete-not-found').hide(); } } else { container.find('.autocomplete-found').show(); container.find('.autocomplete-not-found, .autocomplete-values').hide(); } }); } } }); // Save searchbar instance a.searchbar = searchbar; // Update values function updateValues() { var valuesHTML = ''; var i; for (i = 0; i < a.value.length; i++) { valuesHTML += a.itemTemplate({ value: typeof a.value[i] === 'object' ? a.value[i][a.params.valueProperty] : a.value[i], text: typeof a.value[i] === 'object' ? a.value[i][a.params.textProperty]: a.value[i], inputType: a.inputType, id: a.id, inputName: a.inputName + '-checked', checkbox: a.inputType === 'checkbox', material: material, selected: true }); } container.find('.autocomplete-values ul').html(valuesHTML); } // Handle Inputs container.on('change', 'input[type="radio"], input[type="checkbox"]', function () { var i; var input = this; var value = input.value; var text = $(input).parents('li').find('.item-title').text(); var isValues = $(input).parents('.autocomplete-values').length > 0; var item, itemValue, aValue; if (isValues) { if (a.inputType === 'checkbox' && !input.checked) { for (i = 0; i < a.value.length; i++) { aValue = typeof a.value[i] === 'string' ? a.value[i] : a.value[i][a.params.valueProperty]; if (aValue === value || aValue * 1 === value * 1) { a.value.splice(i, 1); } } updateValues(); if (a.params.onChange) a.params.onChange(a, a.value); } return; } // Find Related Item for (i = 0; i < a.items.length; i++) { itemValue = typeof a.items[i] === 'string' ? a.items[i] : a.items[i][a.params.valueProperty]; if (itemValue === value || itemValue * 1 === value * 1) item = a.items[i]; } // Update Selected Value if (a.inputType === 'radio') { a.value = [item]; } else { if (input.checked) { a.value.push(item); } else { for (i = 0; i < a.value.length; i++) { aValue = typeof a.value[i] === 'string' ? a.value[i] : a.value[i][a.params.valueProperty]; if (aValue === value || aValue * 1 === value * 1) { a.value.splice(i, 1); } } } } // Update Values Block updateValues(); // On Select Callback if ((a.inputType === 'radio' && input.checked || a.inputType === 'checkbox') && a.params.onChange ) { a.params.onChange(a, a.value); } if (backOnSelect && a.inputType === 'radio') { if (a.params.openIn === 'popup') app.closeModal(a.popup); else view.router.back(); } }); // Update Values On Page Init updateValues(); if (a.params.onOpen) a.params.onOpen(a); }; // Show Hide Preloader a.showPreloader = function () { if (a.params.openIn === 'dropdown') { if (a.dropdown) a.dropdown.find('.autocomplete-preloader').addClass('autocomplete-preloader-visible'); } else $('.autocomplete-preloader').addClass('autocomplete-preloader-visible'); }; a.hidePreloader = function () { if (a.params.openIn === 'dropdown') { if (a.dropdown) a.dropdown.find('.autocomplete-preloader').removeClass('autocomplete-preloader-visible'); } else $('.autocomplete-preloader').removeClass('autocomplete-preloader-visible'); }; // Open Autocomplete Page/Popup a.open = function () { if (a.opened) return; a.opened = true; if (a.params.openIn === 'dropdown') { if (!a.dropdown) { a.dropdown = $(a.dropdownTemplate({ preloader: a.params.preloader, preloaderColor: a.params.preloaderColor, material: material, materialPreloaderHtml: app.params.materialPreloaderHtml })); a.dropdown.on('click', 'label', handleDropdownClick); } var listBlock = a.input.parents('.list-block'); if (listBlock.length && a.input.parents('.item-content').length > 0 && a.params.expandInput) { a.input.parents('.item-content').addClass('item-content-dropdown-expand'); } a.positionDropDown(); a.input.parents('.page-content').append(a.dropdown); a.dropdown.addClass('autocomplete-dropdown-in'); a.input.trigger('input'); $(window).on('resize', a.positionDropDown); if (a.params.onOpen) a.params.onOpen(a); } else { $(document).once('pageInit', '.autocomplete-page', a.pageInit); if (a.params.openIn === 'popup') { a.popup = app.popup( '' ); a.popup = $(a.popup); a.popup.once('closed', function () { a.popup = undefined; a.opened = false; if (a.params.onClose) a.params.onClose(a); }); } else { view.router.load({ content: pageHTML }); $(document).once('pageBack', '.autocomplete-page', function () { a.opened = false; if (a.params.onClose) a.params.onClose(a); }); } } }; a.close = function (e) { if (!a.opened) return; if (a.params.openIn === 'dropdown') { if (e && e.type === 'blur' && a.dropdown.find('label.active-state').length > 0) return; a.dropdown.removeClass('autocomplete-dropdown-in').remove(); a.input.parents('.item-content-dropdown-expand').removeClass('item-content-dropdown-expand'); a.opened = false; $(window).off('resize', a.positionDropDown); if (a.params.onClose) a.params.onClose(a); } if (a.params.openIn === 'popup') { if (a.popup) app.closeModal(a.popup); } }; // Init Events a.initEvents = function (detach) { var method = detach ? 'off' : 'on'; if (a.params.openIn !== 'dropdown' && a.opener) { a.opener[method]('click', a.open); } if (a.params.openIn === 'dropdown' && a.input) { a.input[method]('focus', a.open); a.input[method]('input', handleInputValue); if (app.device.android) { $('html')[method]('click', closeOnHTMLClick); } else { a.input[method]('blur', a.close); } } if (detach && a.dropdown) { a.dropdown = null; } }; // Init/Destroy Methods a.init = function () { a.initEvents(); }; a.destroy = function () { a.initEvents(true); a = null; }; // Init a.init(); return a; }; app.autocomplete = function (params) { return new Autocomplete(params); };