2020-10-19 14:48:21 +02:00
2021-12-10 14:23:14 +01:00
import ListColumn from './list-column' ;
import ListAction from './list-action' ;
2021-12-23 13:47:34 +01:00
import { ZeroSchema } from 'zero/schemas' ;
2020-10-19 14:48:21 +02:00
2021-12-23 13:47:34 +01:00
class List implements ZeroSchema
2020-10-19 14:48:21 +02:00
{
2021-12-10 14:23:14 +01:00
alias : string ;
2021-05-08 15:20:23 +02:00
_fetch ;
_filterOptions ;
2020-10-19 14:48:21 +02:00
/**
2020-10-21 11:26:16 +02:00
* Set the default query options which are passed to the fetch function.
2020-10-19 14:48:21 +02:00
* You can extend it to your needs
*/
2020-10-21 11:26:16 +02:00
query = {
2020-10-19 14:48:21 +02:00
// default order by
orderBy : 'createdDate' ,
// order is descending
isDescending : true ,
// current page index
page : 1 ,
// default items per page
pageSize : 25 ,
// search term
search : null ,
// custom filter
filter : null
};
/**
* Overrides the string generation for the label
*/
templateLabel = field => field ;
/**
2021-12-23 14:39:00 +01:00
* Build a link for a row (returns options passed to <ui-link /> or a route name where id-param is automatically inserted)
2020-10-19 14:48:21 +02:00
*/
link = null ;
2021-03-03 15:55:14 +01:00
/**
* Convert a row into a button where the callback is this function
*/
onClick = null ;
2021-12-10 14:23:14 +01:00
columns : ListColumn [] = [];
2020-10-19 14:48:21 +02:00
2021-10-07 15:53:43 +02:00
componentConfig = {
active : false ,
component : null ,
width : 320 ,
block : false
};
2022-01-04 12:58:42 +01:00
scrollContainerSelector = null ;
2020-10-21 11:48:21 +02:00
actions = [];
2021-08-02 12:57:08 +02:00
/**
* Set another list as the base for this list (copies all fields)
* @param {List} list - Base list
* @returns {List}
*/
setBase ( list )
{
this . columns = list . columns . map ( x => new ListColumn ( x . path ). setBase ( x ));
this . actions = list . actions . map ( x => new ListAction ( x . key , x . label , x . icon , x . action , x . autoclose ));
this . query = { ... list . query };
this . templateLabel = list . templateLabel ;
this . link = list . link ;
this . onClick = list . onClick ;
this . actions = [... list . actions ];
return this ;
}
2020-11-19 18:09:59 +01:00
/**
* Converts the list parameters (like page, search, filter, ...) to a vue router query
*/
paramsToQuery = params =>
{
let values : any = {};
if ( params . page !== this . query . page )
{
values . page = params . page ;
}
if ( params . isDescending !== this . query . isDescending || params . orderBy !== this . query . orderBy )
{
values . by = params . orderBy || this . query . orderBy ;
values . desc = params . isDescending || this . query . isDescending ;
}
if ( !! params . search )
{
values . search = params . search ;
}
if ( params . filter && params . filter . id )
{
values . filter = params . filter . id ;
}
return values ;
};
/**
* Converts an URL query string to list parameters
*/
queryToParams = query =>
{
if ( ! query )
{
return {};
}
let values = JSON . parse ( JSON . stringify ( this . query ));
if ( query . page )
{
values . page = + query . page || this . query . page ;
}
if ( query . by )
{
values . orderBy = query . by ;
}
if ( query . desc )
{
values . isDescending = query . desc === "true" || query . desc === true ;
}
if ( query . search )
{
values . search = query . search ;
}
if ( query . filter )
{
values . filter = values . filter || {};
values . filter . id = query . filter ;
}
return values ;
};
2020-10-19 14:48:21 +02:00
constructor ( alias )
{
2021-12-10 14:23:14 +01:00
this . alias = alias ;
2020-10-19 14:48:21 +02:00
}
get filterOptions ()
{
2021-05-08 15:20:23 +02:00
return this . _filterOptions ;
2020-10-19 14:48:21 +02:00
}
/**
* Specify a list column
* @param {string} path - Model path
* @param {object} [options] - Custom options
* @param {string} [options.label] - A custom label for this column (otherwise it's generated via `templateLabel`)
* @param {boolean} [options.hideLabel=false] - Hide the column label
2021-08-06 14:37:00 +02:00
* @param {number} [options.index] - Custom position for this column
2020-10-19 14:48:21 +02:00
* @param {number} [options.width] - Custom width of the column in px
2021-10-15 13:04:05 +02:00
* @param {boolean} [options.canSort=false] - Disable/enable sorting within this column
2020-10-19 14:48:21 +02:00
* @param {string} [options.class] - Append HTML class to the generated cells
* @returns {ListColumn}
*/
column ( path , options )
{
2020-11-19 14:57:00 +01:00
let column = this . columns . find ( x => x . path === path );
if ( ! column )
{
column = new ListColumn ( path , options );
2021-08-06 14:37:00 +02:00
if ( options && options . index > - 1 )
{
this . columns . splice ( options . index , 0 , column );
}
else
{
this . columns . push ( column );
}
2020-11-19 14:57:00 +01:00
}
else
{
column . options = { ... column . options , ...( options || {}) };
}
2020-10-19 14:48:21 +02:00
return column ;
}
2021-08-06 14:37:00 +02:00
/**
* Removes a list column
* @param {string} path - Model path
*/
removeColumn ( path )
{
let column = this . columns . find ( x => x . path === path );
if ( column != null )
{
this . columns . splice ( this . columns . indexOf ( column ), 1 );
}
}
2021-10-07 15:53:43 +02:00
/**
* Use a component instead of columns
* @param {object} component - The custom vue component
* @param {object} [options] - Custom options
* @param {string} [options.width=320] - Desired width of an item (in a grid)
* @param {boolean} [options.block=false] - Full width per item, therefore block/list display
*/
component ( component , options ? )
{
options = options || {};
this . componentConfig = {
active : component != null ,
component : component ,
width : options.width || 320 ,
block : options.block || false
};
}
2020-10-21 11:48:21 +02:00
/**
* Add an action to the list header (only used when it is attached to <ui-table-filter />)
* @param {string} key - Alias to refer to
* @param {string} label - Dropdown-item label
* @param {string} icon - Displayed dropdown-item icon
* @param {function} callback - Called when the action button is clicked (including dropdown options as parameter)
* @param {boolean} [autoclose=true] - Autoclose the actions overlay when this action is clicked
* @returns {ListAction}
*/
action ( key , label , icon , callback , autoclose )
{
const action = new ListAction ( key , label , icon , callback );
action . autoclose = typeof autoclose === 'undefined' ? true : autoclose ;
this . actions . push ( action );
return action ;
}
/**
* Shortcut for an "export" action with predefined key, label and icon
* @param {Promise} callback - A promise which is called when the action button is clicked (including dropdown options as parameter)
* @returns {ListColumn}
*/
export ( callback )
{
return this . action ( 'export' , '@ui.export.action' , 'fth-share' , opts =>
{
opts . loading ( true );
2021-08-04 15:30:20 +02:00
callback (). then ( _ =>
{
opts . loading ( false );
opts . hide ();
});
2020-10-21 11:48:21 +02:00
}, false );
}
2020-10-19 14:48:21 +02:00
/**
* Get list items with this function
* @param {function} callback - This function is called when the list is requested (parameter is the filter object). You should either return a Promise or an Array here.
*/
onFetch ( callback )
{
2021-05-08 15:20:23 +02:00
this . _fetch = callback ;
2020-10-19 14:48:21 +02:00
}
/**
* Fetch items with the specified filter
*/
fetch ( filter )
{
2021-05-08 15:20:23 +02:00
return this . _fetch ( filter );
2020-10-19 14:48:21 +02:00
}
/**
* Filter a list by providing an editor renderer and a default template.
* This activates the Filter button and overlay in the <ui-table-filter /> component.
* @param {Editor} editor - An editor renderer which opens in an overlay
* @param {object} template - The default template to use when creating a new filter
*/
useFilter ( editor , template )
{
2021-05-08 15:20:23 +02:00
this . _filterOptions = { editor , template };
2020-10-19 14:48:21 +02:00
}
};
export default List ;