/* ======================================= LIST TABLE ======================================= */ import { ActiveRow } from './_active-row'; import { BeforeUnload } from '../_before-unload'; import EnhancedSelect from '../_enhanced-select'; import Globals from './_globals'; import Settings from '../../config/_settings'; import Tooltip from '../_tooltip'; import { Utils } from '../../utils/_utils'; export default class ListTable { doingAjax: any = null; isRowExpanding = {}; constructor( private settings: Settings, private globals: Globals, private toolTip: Tooltip, private enhancedSelect: EnhancedSelect ) { // Bind events. this.events(); } /** * Bind List Table events */ events() { // Bind active class rows. ActiveRow.addActiveClassRow(this.globals.$atumTable); // Calculate compounded stocks. this.calculateCompoundedStocks(); this.globals.$atumList // // Trigger expanding/collapsing event in inheritable products. // ------------------------------------------ .on('click', '.calc_type .has-child', (evt: JQueryEventObject) => $(evt.currentTarget).closest('tr').trigger('atum-list-expand-row') ) // // Triggers the expand/collapse row action. // .on('atum-list-expand-row', 'tbody tr', (evt: JQueryEventObject, expandableRowClass: string, stopRowSelector: string, stopPropagation: boolean) => { this.expandRow($(evt.currentTarget), expandableRowClass, stopRowSelector, stopPropagation); }) // // Expandable rows' checkboxes. // ---------------------------- .on('change', '.check-column input:checkbox', (evt: JQueryEventObject) => this.checkDescendats( $(evt.currentTarget) )) // // "Control all products" button. // ------------------------------ .on('click', '#control-all-products', (evt: JQueryEventObject) => { let $button: JQuery = $(evt.currentTarget); $.ajax({ url : window['ajaxurl'], method : 'POST', dataType : 'json', beforeSend: () => $button.prop('disabled', true).after(''), data : { token : $button.data('nonce'), action: 'atum_control_all_products', }, success : () => location.reload(), }); }); // // Global save for edited cells. // ----------------------------- $('body').on('click', '#atum-update-list', (evt: JQueryEventObject) => this.saveData( $(evt.currentTarget) )); // // Warn the user about unsaved changes before navigating away. // ----------------------------------------------------------- BeforeUnload.addPrompt( () => !this.globals.$editInput.val() ); // Display hidden footer. $(window).on('load', () => $('#wpfooter').show()); } /** * Send the ajax call and replace table parts with updated version */ updateTable() { if (this.doingAjax && this.doingAjax.readyState !== 4) { this.doingAjax.abort(); } // Overwrite the filterData with the URL hash parameters this.globals.filterData = $.extend(this.globals.filterData, { view : $.address.parameter('view') || '', product_cat : $.address.parameter('product_cat') || '', product_type : $.address.parameter('product_type') || '', supplier : $.address.parameter('supplier') || '', extra_filter : $.address.parameter('extra_filter') || '', paged : $.address.parameter('paged') || '', order : $.address.parameter('order') || '', orderby : $.address.parameter('orderby') || '', search_column : $.address.parameter('search_column') || '', sold_last_days: $.address.parameter('sold_last_days') || '', s : $.address.parameter('s') || '', }); this.doingAjax = $.ajax({ url : window['ajaxurl'], dataType : 'json', method : 'GET', data : this.globals.filterData, beforeSend: () => { this.toolTip.destroyTooltips(); this.addOverlay(); }, // Handle the successful result. success : (response: any) => { this.doingAjax = null; if (typeof response === 'undefined' || !response) { return false; } // Update table with the coming rows. if (typeof response.rows !== 'undefined' && response.rows.length) { this.globals.$atumList.find('#the-list').html(response.rows); this.restoreMeta(); } // Change page url parameter. if (response.paged > 0) { $.address.parameter('paged', response.paged); } // Update column headers for sorting. if (typeof response.column_headers !== 'undefined' && response.column_headers.length) { this.globals.$atumList.find('table').not('.cloned').find('tr.item-heads').html(response.column_headers); } // Update the views filters. if (typeof response.views !== 'undefined' && response.views.length) { this.globals.$atumList.find('.subsubsub').replaceWith(response.views); } // Update table navs. if (typeof response.extra_t_n !== 'undefined') { if (response.extra_t_n.top.length) { this.globals.$atumList.find('.tablenav.top').replaceWith(response.extra_t_n.top); } if (response.extra_t_n.bottom.length) { this.globals.$atumList.find('.tablenav.bottom').replaceWith(response.extra_t_n.bottom); } } // Update the totals row. if (typeof response.totals !== 'undefined') { this.globals.$atumList.find('table').not('.cloned').find('tfoot tr.totals').html(response.totals); } // If there are active filters, show the reset button. if ($.address.parameterNames().length) { this.globals.$atumList.find('.reset-filters').removeClass('hidden'); } // Regenerate the UI. this.toolTip.addTooltips(); this.enhancedSelect.maybeRestoreEnhancedSelect(); ActiveRow.addActiveClassRow(this.globals.$atumTable); this.removeOverlay(); this.calculateCompoundedStocks(); // Custom trigger after updating. this.globals.$atumList.trigger('atum-table-updated'); }, error : () => this.removeOverlay(), }); } /** * Add the overlay effect while loading data */ addOverlay() { const $tableWrapper: any = $('.atum-table-wrapper'); $tableWrapper.block({ message : null, overlayCSS: { background: '#000', opacity : 0.5, }, }); } /** * Remove the overlay effect once the data is fully loaded */ removeOverlay() { const $tableWrapper: any = $('.atum-table-wrapper'); $tableWrapper.unblock(); } /** * Set the table cell value with right format * * @param jQuery $metaCell The cell where will go the value. * @param String|Number value The value to set in the cell. */ setCellValue($metaCell: JQuery, value: string) { let symbol: string = $metaCell.data('symbol') || '', currencyPos: string = this.globals.$atumTable.data('currency-pos'); if (value === '') { value = this.settings.get('emptyCol'); } else if (symbol) { value = currencyPos === 'left' ? symbol + value : value + symbol; } $metaCell.addClass('unsaved').text(value); } /** * Restore the edited meta after loading new table rows */ restoreMeta() { let editedCols: any = this.globals.$editInput.val(); if (editedCols) { editedCols = $.parseJSON(editedCols); $.each( editedCols, (itemId: string, meta: any) => { // Filter the meta cell that was previously edited. let $metaCell: JQuery = $('tr[data-id="' + itemId + '"] .set-meta'); if ($metaCell.length) { $.each(meta, (key: string, value: any) => { $metaCell = $metaCell.filter('[data-meta="' + key + '"]'); if ($metaCell.length) { this.setCellValue($metaCell, value); // Add the extra meta too. let extraMeta: any = $metaCell.data('extra-meta'); if (typeof extraMeta === 'object') { $.each(extraMeta, (index: number, extraMetaObj: any) => { // Restore the extra meta from the edit input if (editedCols[itemId].hasOwnProperty(extraMetaObj.name)) { extraMeta[index]['value'] = editedCols[itemId][extraMetaObj.name]; } }) $metaCell.data('extra-meta', extraMeta); } } }); } }); } } /** * Every time a cell is edited, update the input value * * @param jQuery $metaCell The table cell that is being edited. * @param jQuery $popover The popover attached to the above cell. */ updateEditedColsInput($metaCell: JQuery, $popover: JQuery) { let editedCols: any = this.globals.$editInput.val(), itemId: number = $metaCell.closest('tr').data('id'), meta: string = $metaCell.data('meta'), symbol: string = $metaCell.data('symbol') || '', custom: string = $metaCell.data('custom') || 'no', currency: string = $metaCell.data('currency') || '', value: any = symbol ? $metaCell.text().replace(symbol, '') : $metaCell.text(), newValue: any = $popover.find('.meta-value').val(); // Update the cell value. this.setCellValue($metaCell, newValue); // Initialize the JSON object. if (editedCols) { editedCols = $.parseJSON(editedCols); } editedCols = editedCols || {}; if (!editedCols.hasOwnProperty(itemId)) { editedCols[itemId] = {}; } if (!editedCols[itemId].hasOwnProperty(meta)) { editedCols[itemId][meta] = {}; } // Add the meta value to the object. editedCols[itemId][meta] = newValue; editedCols[itemId][meta + '_custom'] = custom; editedCols[itemId][meta + '_currency'] = currency; // Add the extra meta data (if any). if ($popover.hasClass('with-meta')) { let extraMeta: any = $metaCell.data('extra-meta'); $popover.find('input').not('.meta-value').each( (index: number, input: Element) => { const $input: JQuery = $(input), value: any = $input.val(), name: string = $input.attr('name'); editedCols[itemId][name] = value; // Save the meta values in the cell data for future uses. if (typeof extraMeta === 'object') { $.each(extraMeta, (index: number, elem: any) => { if (elem.name === name) { extraMeta[index]['value'] = value; return false; } }); } }); } this.globals.$editInput.val( JSON.stringify(editedCols) ); this.globals.$atumList.trigger('atum-edited-cols-input-updated', [$metaCell]); } /** * Check if we need to add the Update button */ maybeAddSaveButton() { let $tableTitle: JQuery = this.globals.$atumList.siblings('.wp-heading-inline'); if (!$tableTitle.find('#atum-update-list').length) { $tableTitle.append($('