UNPKG

landmark-serve

Version:

Web Application Framework and Admin GUI / Content Management System built on Express.js and Mongoose

391 lines (336 loc) 11.6 kB
/*global jQuery, moment, _, Landmark, alert, confirm, require */ jQuery(function($) { // Import var queryfilterUtil = require('queryfilter'), querystringUtil = require('querystring'); // Cache items var $filters = $('#list-filters'); /** Create Item */ $('.btn-create-item').click(function(){ var $form = $(this).closest('form'); $form.find('.form').show(); $form.find('.toolbar-default').hide(); $form.find('.toolbar-create').show(); $form.find('input[type=text]').first().focus(); }); // Autofocus the search field if there has been a search if ($('.search-list input').val()) { setTimeout(function() { $('.search-list input').focus(); },10); } $('.btn-cancel-create-item').click(function() { var $form = $(this).closest('form'); $form.find('.form').hide(); $form.find('.toolbar-default').show(); $form.find('.toolbar-create').hide(); }); /** Columns */ $('.btn-toggle-column').click(function() { var key = $(this).data('col'); if (_.contains(Landmark.list.cols, key)) { $.addSearchParam({ cols: _.without(Landmark.list.cols, key).join(',') }, true); } else { Landmark.list.cols.push(key); $.addSearchParam({ cols: Landmark.list.cols.join(',') }, true); } }); /** Filtering */ var checkFiltersStatus = function() { var enabledFilters = $('.filter.active'), enabledPaths = _.map(enabledFilters, function(i) { return $(i).data('path'); }); $('.list-filters-action')[enabledFilters.length ? 'show' : 'hide'](); $('.add-list-filter').each(function() { var path = $(this).data('path'); $(this).parent()[_.contains(enabledPaths, path) ? 'addClass' : 'removeClass']('disabled'); }); }; checkFiltersStatus(); $('.add-list-filter').click(function() { var path = $(this).data('path'); var $filter = $('.filter[data-path="' + path + '"]').addClass('active'); $(window).scrollTop(0); checkFiltersStatus(); var $input = $filter.find('input[type=text]'); if ($input.length) { try { $input[0].focus(); } catch(e) {} } }); // Handle switching between number types // If the option selected is between, then show the between range inputs // otherwise show the standard input field $filters.on('change', '.filter .btn-group-operator :radio[name=options]', function(){ // Fetch the radio that is now checked var $radio = $(this); // Fetch the field this is for var $field = $radio.parents('.filter-options:first'); // As the value isn't stored on the radio, fetch the value from the parent button's data type // @BEN: this seems silly var numericFilter = $radio.parent().data('value'); // Whether or not the range inputs should be shown or not var showRange = numericFilter === 'bt'; // Toggle the displays of the fields $field.find('.filter-input-range').toggle(showRange).siblings('.filter-input-standard').toggle(!showRange); }); // Ensure that the correct fields are shown initially $filters.find('.filter .btn-group-operator .btn.active :radio').trigger('change'); $('.clear-filter').click(function() { $(this).closest('.filter').removeClass('active'); checkFiltersStatus(); }); // -------------------------------- // Recent Searches if (window.localStorage) { var querystring = querystringUtil.parse(document.location.search.replace('?', '')); var recentSearches; var $searchDropdown = $('.js-recent-searches'); var $searches = $searchDropdown.find('ul'); var key = 'landmark-recentsearches-' + Landmark.list.path; // Prase the recent searches try { recentSearches = JSON.parse(window.localStorage.getItem(key) || 'false'); } catch (err) {} if (Array.isArray(recentSearches) === false) { recentSearches = []; } // Add the new search // If it exists, remove it where it was, and add it to the start // If it doesn't exist, just add it to the start if (querystring.q) { var existingIndex = recentSearches.indexOf(querystring.q); if (existingIndex !== -1) { recentSearches = recentSearches.slice(0, existingIndex).concat(recentSearches.slice(existingIndex+1)); } recentSearches.unshift(querystring.q); recentSearches = recentSearches.slice(0, 20); // only keep the 20 most recent window.localStorage.setItem(key, JSON.stringify(recentSearches)); } // Add the recent searches to the dom if (recentSearches.length !== 0) { recentSearches.forEach(function(recentSearch){ var filter = queryfilterUtil.QueryFilters.create(recentSearch); var readablefilter = filter.toHumanString().replace(/([A-Z])/g, ' $1').toLowerCase(); // separate camel cased words var querystring = querystringUtil.parse(document.location.search.replace('?', '')); querystring.q = recentSearch; querystring = querystringUtil.stringify(querystring); $('<a>', { href: '?' + querystring, text: readablefilter.charAt(0).toUpperCase() + readablefilter.slice(1) }).appendTo($('<li>').appendTo($searches)); }); $searchDropdown.removeClass('hidden'); } } // -------------------------------- // Filters var parseValueWithType = function(type, value){ var result = null; switch (type) { case 'number': case 'money': value = Number(value); if (value && isNaN(value) === false) { result = value; } break; case 'date': case 'datetime': value = moment(value); if (value && value.isValid()) { result = value.format('YYYY-MM-DD'); } break; default: result = value; break; } return result; }; $filters.submit(function(e) { e.preventDefault(); var filterQueryString = [], search = $(this).find('.js-search-list').val(), cancelled = false; $(this).find('.filter.active').each(function() { var $filter = $(this), $ops = $filter.find('.btn.active[data-opt]'), // active options data = { type: $filter.data('type'), path: $filter.data('path') }, queryFilter = queryfilterUtil.QueryFilter.create(), value; $ops.each(function() { data[$(this).data('opt')] = $(this).data('value'); }); queryFilter.type = data.type; queryFilter.key = data.path; queryFilter.inverse = data.inv; queryFilter.exact = data.exact; queryFilter.operator = data.operator; if ( data.operator === 'bt' ) { value = [ parseValueWithType(data.type, $filter.find('input.filter-input-range1').val()), parseValueWithType(data.type, $filter.find('input.filter-input-range2').val()) ]; if ( value[0] == null || value[1] == null ) { alert('Both fields are required when specifying a range'); cancelled = true; return false; } queryFilter.value = value; } else { switch (data.type) { case 'text': case 'textarea': case 'html': case 'email': case 'url': case 'key': case 'number': case 'money': case 'date': case 'datetime': if (value = parseValueWithType(data.type, $filter.find('input[name=value]').val())) { queryFilter.value = value; } break; case 'select': if (value = parseValueWithType(data.type, $filter.find('select[name=value]').val())) { queryFilter.value = value; } break; case 'location': value = []; $filter.find('input[type=text]').each(function() { value.push($(this).val()); }); queryFilter.value = value; break; case 'boolean': case 'cloudinaryimage': case 'cloudinaryimages': case 's3file': if (data.value) { // where is this defined??? queryFilter.value = value; } break; case 'relationship': if (value = parseValueWithType(data.type, $filter.find('input[type=hidden]').val())) { queryFilter.value = value; } break; } } if (queryFilter.value != null) { filterQueryString.push(queryFilter.toString()); } }); if (cancelled === false) { $.addSearchParam({ search: search || undefined, q: filterQueryString.join(';') || undefined }, true); } }); /** List Controls */ $('table.items-list tbody').on('mouseenter mouseleave', 'tr a.control-delete', function(e) { if (e.type == 'mouseenter') { $(this).closest('tr').addClass('delete-hover'); } else { $(this).closest('tr').removeClass('delete-hover'); } }).on('click', 'tr a.control-delete', function(e) { e.preventDefault(); if (!confirm('Are you sure you want to delete this ' + Landmark.list.singular.toLowerCase() + '?')) { return false; } var $row = $(this).closest('tr'), $table = $(this).closest('table'); $row.addClass('delete-inprogress'); var onError = function(err) { if (err && err.responseJSON) { err = err.responseJSON; } var errorMessage = 'There was an error deleting the ' + Landmark.list.singular.toLowerCase() + '.'; if (err && err.error) { errorMessage += ' ( error: ' + err.error + ')'; } alert(errorMessage); $row.removeClass('delete-inprogress'); }; $.ajax('/landmark/api/' + Landmark.list.path + '/delete', { data: Landmark.csrf({ id: $row.attr('id') }), dataType: 'json' }).done(function(rtn) { if (rtn.success) { // decrement total Landmark.items.total--; Landmark.items.totalPages = Math.ceil(Landmark.items.total / Landmark.list.perPage); // update .list-header if (!Landmark.items.total) { $('.page-header.list-header').addClass('empty-list'); $('.items-total').text('No ' + Landmark.list.plural.toLowerCase() + ' found.'); $('.search-sort').remove(); $('form#list-filters').remove(); $('.list-pagination').remove(); $('.items-list-wrapper').remove(); return; } if (Landmark.items.currentPage > Landmark.items.totalPages) { window.location.href = '/landmark/' + Landmark.list.path + '/' + Landmark.items.previous; return; } $row.remove(); $('.items-total').text(Landmark.items.total + ' ' + (Landmark.items.total == 1 ? Landmark.list.singular : Landmark.list.plural)); // update .list-pagination if (Landmark.items.totalPages == 1) { $('.list-pagination .count').text('Showing ' + Landmark.items.total + ' ' + (Landmark.items.total == 1 ? Landmark.list.singular : Landmark.list.plural)); } if (Landmark.items.totalPages > 1) { if(Landmark.items.last > Landmark.items.total) { Landmark.items.last = Landmark.items.total; $('.list-pagination .count').text('Showing ' + Landmark.items.first + ' to ' + Landmark.items.last + ' of ' + Landmark.items.total); } else { $.ajax('/landmark/api/' + Landmark.list.path + '/fetch', { data: Landmark.csrf({ items: { first: Landmark.items.first, last: Landmark.items.last, total: Landmark.items.total, currentPage: Landmark.items.currentPage, totalPages: Landmark.items.totalPages }, search: Landmark.search, filters: Landmark.filters, cols: Landmark.list.cols, sort: Landmark.sort, csrf_query: Landmark.csrf_query, q: Landmark.query }), dataType: 'json' }).done(function(rtn) { if (rtn.success) { $table.append(rtn.row); $('.list-pagination').html(rtn.pagination); } else { onError(rtn); } }).error(onError); } } } else { onError(rtn); } }).error(onError); }); $('a.control-sort').hover(function() { $(this).closest('tr').addClass('sort-hover'); }, function() { $(this).closest('tr').removeClass('sort-hover'); }); });