@@ -166,8 +166,6 @@ const defaultSortItemsCallback = (subModel: ActionListItemModel[]): void => {
166166 } ) ;
167167} ;
168168
169- // type ImmediateFilter = "immediate" | "debounced" | undefined;
170-
171169@Component ( {
172170 tag : "ch-action-list-render" ,
173171 styleUrl : "action-list-render.scss" ,
@@ -206,6 +204,16 @@ export class ChActionListRender {
206204 */
207205 @Prop ( ) readonly editableItems : boolean = DEFAULT_EDITABLE_ITEMS_VALUE ;
208206
207+ /**
208+ * Callback that is executed when and item requests to be fixed/unfixed.
209+ * If the callback is not defined, the item will be fixed/unfixed without
210+ * further confirmation.
211+ */
212+ @Prop ( ) readonly fixItemCallback ?: (
213+ itemInfo : ActionListItemActionable ,
214+ newFixedValue : boolean
215+ ) => Promise < boolean > ;
216+
209217 /**
210218 * This property lets you define the model of the control.
211219 */
@@ -377,9 +385,66 @@ export class ChActionListRender {
377385
378386 /**
379387 * Fired when an item is clicked and `selection === "none"`.
388+ * Applies for items that have `type === "actionable"` or
389+ * (`type === "group"` and `expandable === true`)
380390 */
381391 @Event ( ) itemClick : EventEmitter < ActionListItemModelExtended > ;
382392
393+ /**
394+ * Adds an item in the control.
395+ *
396+ * If the item already exists, the operation is canceled.
397+ *
398+ * If the `groupParentId` property is specified the item is added in the
399+ * group determined by `groupParentId`. It only works if the item to add
400+ * has `type === "actionable"`
401+ */
402+ @Method ( )
403+ async addItem (
404+ itemInfo : ActionListItemModel ,
405+ groupParentId ?: string
406+ ) : Promise < void > {
407+ // Already exists
408+ if ( this . #flattenedModel. get ( itemInfo . id ) ) {
409+ return ;
410+ }
411+
412+ if ( groupParentId ) {
413+ const parentGroup = this . #flattenedModel. get ( groupParentId ) ;
414+
415+ // The parent group does not exists or it isn't a group
416+ if (
417+ ! parentGroup ||
418+ parentGroup . item . type !== "group" ||
419+ itemInfo . type !== "actionable"
420+ ) {
421+ return ;
422+ }
423+
424+ parentGroup . item . items . push ( itemInfo ) ;
425+ this . #flattenedModel. set ( itemInfo . id , {
426+ item : itemInfo ,
427+ parentItem : parentGroup . item
428+ } ) ;
429+
430+ // Sort items in parent model
431+ this . #sortModel( parentGroup . item . items ) ;
432+ }
433+ // Item is placed at the root
434+ else {
435+ this . model . push ( itemInfo ) ;
436+ this . #flattenedModel. set ( itemInfo . id , {
437+ item : itemInfo ,
438+ root : this . model
439+ } ) ;
440+
441+ // Sort items in parent model
442+ this . #sortModel( this . model ) ;
443+ }
444+
445+ forceUpdate ( this ) ;
446+ }
447+
383448 /**
384449 * Given a list of ids, it returns an array of the items that exists in the
385450 * given list.
@@ -391,6 +456,29 @@ export class ChActionListRender {
391456 return this . #getItemsInfo( itemsId ) ;
392457 }
393458
459+ /**
460+ * Remove the item and all its descendants from the control.
461+ */
462+ @Method ( )
463+ async removeItem ( itemId : string ) {
464+ const itemUIModel = this . #flattenedModel. get ( itemId ) ;
465+
466+ if ( ! itemUIModel ) {
467+ return ;
468+ }
469+
470+ // Remove all descendants
471+ if ( itemUIModel . item . type === "group" ) {
472+ const items = itemUIModel . item . items ;
473+
474+ items . forEach ( item => {
475+ this . #flattenedModel. delete ( item . id ) ;
476+ } ) ;
477+ }
478+
479+ this . #removeItem( itemUIModel ) ;
480+ }
481+
394482 #getItemsInfo = ( itemsId : string [ ] ) : ActionListItemModelExtended [ ] => {
395483 const actionListItemsInfo : ActionListItemModelExtended [ ] = [ ] ;
396484
@@ -413,7 +501,25 @@ export class ChActionListRender {
413501
414502 const itemUIModel = this . #flattenedModel. get ( detail . itemId ) ;
415503 const itemInfo = itemUIModel . item as ActionListItemActionable ;
416- itemInfo . fixed = detail . value ;
504+
505+ if ( ! this . fixItemCallback ) {
506+ this . #updateItemFix( itemUIModel , itemInfo , detail . value ) ;
507+ return ;
508+ }
509+
510+ this . fixItemCallback ( itemInfo , detail . value ) . then ( acceptChange => {
511+ if ( acceptChange ) {
512+ this . #updateItemFix( itemUIModel , itemInfo , detail . value ) ;
513+ }
514+ } ) ;
515+ }
516+
517+ #updateItemFix = (
518+ itemUIModel : ActionListItemModelExtended ,
519+ itemInfo : ActionListItemActionable ,
520+ newFixedValue : boolean
521+ ) => {
522+ itemInfo . fixed = newFixedValue ;
417523
418524 // Sort items in parent model
419525 this . #sortModel(
@@ -423,7 +529,7 @@ export class ChActionListRender {
423529
424530 // Queue a re-render to update the fixed binding and the order of the items
425531 forceUpdate ( this ) ;
426- }
532+ } ;
427533
428534 @Listen ( "remove" )
429535 onRemove ( event : ChActionListItemCustomEvent < string > ) {
@@ -491,6 +597,9 @@ export class ChActionListRender {
491597 const itemInfo = this . #getItemOrGroupInfo( actionListItemOrGroup . id ) ;
492598 this . #checkIfMustExpandCollapseGroup( itemInfo ) ;
493599
600+ if ( itemInfo . type === "group" && ! itemInfo . expandable ) {
601+ return ;
602+ }
494603 this . itemClick . emit ( this . #flattenedModel. get ( itemInfo . id ) ) ;
495604 } ;
496605
@@ -594,15 +703,21 @@ export class ChActionListRender {
594703 const parentArray =
595704 ( itemUIModel as ActionListItemModelExtendedRoot ) . root ??
596705 ( itemUIModel as ActionListItemModelExtendedGroup ) . parentItem . items ;
597- const itemInfo = itemUIModel . item as ActionListItemActionable ;
706+ const itemToRemoveId = itemUIModel . item . id ;
598707
599708 const itemToRemoveIndex = parentArray . findIndex (
600- el => ( el as ActionListItemActionable ) . id === itemInfo . id
709+ el => el . id === itemToRemoveId
601710 ) ;
602711
603- // Remove the UI model from the previous parent. The equality function
604- // must be by index, not by object reference
605- removeElement ( parentArray , itemToRemoveIndex ) ;
712+ // In some situations, the user could remove the item before the
713+ // "removeItemCallback" promise is resolved
714+ if ( itemToRemoveIndex > - 1 ) {
715+ // Remove the UI model from the previous parent. The equality function
716+ // must be by index, not by object reference
717+ removeElement ( parentArray , itemToRemoveIndex ) ;
718+ }
719+
720+ this . #flattenedModel. delete ( itemToRemoveId ) ;
606721
607722 // Queue a re-render
608723 forceUpdate ( this ) ;
0 commit comments