Project

General

Profile

« Previous | Next » 

Revision ae69029f

Added by Andreas Kohlbecker over 3 years ago

fix #7846 editor context information shown as breadcrumbs in the toolbar of popup editors

View differences:

src/main/java/eu/etaxonomy/cdm/vaadin/event/AbstractEditorAction.java
117 117
        return context;
118 118
    }
119 119

  
120
    public static class EditorActionContext {
121

  
122
        Object parentEntity;
123

  
124
        AbstractView parentView;
125

  
126
        /**
127
         * @param parentEntity
128
         * @param parentView
129
         */
130
        public EditorActionContext(Object parentEntity, AbstractView parentView) {
131
            super();
132
            this.parentEntity = parentEntity;
133
            this.parentView = parentView;
134
        }
135

  
136
        /**
137
         * @return the parentEntity
138
         */
139
        public Object getParentEntity() {
140
            return parentEntity;
141
        }
142

  
143
        /**
144
         * @return the parentView
145
         */
146
        public AbstractView getParentView() {
147
            return parentView;
148
        }
149

  
150

  
151

  
152
    }
153

  
154 120
}
src/main/java/eu/etaxonomy/cdm/vaadin/event/EditorActionContext.java
1
/**
2
* Copyright (C) 2018 EDIT
3
* European Distributed Institute of Taxonomy
4
* http://www.e-taxonomy.eu
5
*
6
* The contents of this file are subject to the Mozilla Public License Version 1.1
7
* See LICENSE.TXT at the top of this package for the full license terms.
8
*/
9
package eu.etaxonomy.cdm.vaadin.event;
10

  
11
import com.vaadin.ui.Field;
12

  
13
import eu.etaxonomy.vaadin.mvp.AbstractPopupEditor;
14
import eu.etaxonomy.vaadin.mvp.AbstractView;
15
import eu.etaxonomy.vaadin.util.PropertyIdPath;
16

  
17
public class EditorActionContext {
18

  
19
    Object parentEntity;
20

  
21
    AbstractView parentView;
22

  
23
    /**
24
     * The field in the parent view to which the child view is related to.
25
     */
26
    Field<?> targetField;
27

  
28
    /**
29
     * @param parentEntity
30
     * @param parentView
31
     */
32
    public EditorActionContext(Object parentEntity, AbstractView parentView) {
33
        super();
34
        this.parentEntity = parentEntity;
35
        this.parentView = parentView;
36
    }
37

  
38
    /**
39
     * TODO rename to getParentBean()
40
     *
41
     * @return the parentEntity
42
     */
43
    public Object getParentEntity() {
44
        return parentEntity;
45
    }
46

  
47
    /**
48
     * @return the parentView
49
     */
50
    public AbstractView getParentView() {
51
        return parentView;
52
    }
53

  
54
    /**
55
     * @param targetField
56
     */
57
    public void setTargetField(Field<?> targetField) {
58
        this.targetField = targetField;
59
    }
60

  
61
    public Field<?> getTargetField() {
62
        return targetField;
63
    }
64

  
65
    public PropertyIdPath getTargetPropertyIdPath(){
66
        if(parentView instanceof AbstractPopupEditor && targetField != null){
67
            return ((AbstractPopupEditor)getParentView()).boundPropertyIdPath(targetField);
68
        } else {
69
            return null;
70
        }
71
    }
72

  
73

  
74

  
75
}
src/main/java/eu/etaxonomy/cdm/vaadin/event/EditorActionContextFormat.java
1
/**
2
* Copyright (C) 2018 EDIT
3
* European Distributed Institute of Taxonomy
4
* http://www.e-taxonomy.eu
5
*
6
* The contents of this file are subject to the Mozilla Public License Version 1.1
7
* See LICENSE.TXT at the top of this package for the full license terms.
8
*/
9
package eu.etaxonomy.cdm.vaadin.event;
10

  
11
public class EditorActionContextFormat {
12

  
13
    public enum TargetInfoType {
14
        PROPERTIES, FIELD_CAPTION;
15
    }
16

  
17
    /**
18
     *
19
     */
20
    public boolean doClassName;
21
    /**
22
     *
23
     */
24
    public boolean doTargetInfo;
25
    /**
26
     *
27
     */
28
    public boolean classNameForMissingTargetData;
29
    /**
30
     *
31
     */
32
    public boolean doCreateOrNew;
33

  
34
    /**
35
     * The name of the html tag to be used
36
     */
37
    public String tagName = "span";
38

  
39
    /**
40
     * additional class attributes
41
     */
42
    public String classAttributes = "";
43

  
44
    public TargetInfoType targetInfoType = TargetInfoType.PROPERTIES;
45

  
46

  
47
    /**
48
     *
49
     */
50
    public EditorActionContextFormat(boolean doClassName, boolean doProperties, boolean classNameForMissingPropertyPath,
51
            boolean doCreateOrNew, TargetInfoType targetInfoType, String classAttributes) {
52
        this.doClassName = doClassName;
53
        this.doTargetInfo = doProperties;
54
        this.classNameForMissingTargetData = classNameForMissingPropertyPath;
55
        this.doCreateOrNew = doCreateOrNew;
56
        this.targetInfoType = targetInfoType;
57
        this.classAttributes = classAttributes;
58
    }
59
}
src/main/java/eu/etaxonomy/cdm/vaadin/event/EditorActionContextFormatter.java
1
/**
2
* Copyright (C) 2018 EDIT
3
* European Distributed Institute of Taxonomy
4
* http://www.e-taxonomy.eu
5
*
6
* The contents of this file are subject to the Mozilla Public License Version 1.1
7
* See LICENSE.TXT at the top of this package for the full license terms.
8
*/
9
package eu.etaxonomy.cdm.vaadin.event;
10

  
11
import java.util.Stack;
12

  
13
import org.apache.commons.lang3.StringUtils;
14

  
15
import com.vaadin.ui.Component;
16

  
17
import eu.etaxonomy.cdm.model.common.CdmBase;
18
import eu.etaxonomy.cdm.ref.TypedEntityReference;
19
import eu.etaxonomy.cdm.vaadin.event.EditorActionContextFormat.TargetInfoType;
20
import eu.etaxonomy.cdm.vaadin.model.CdmEntityAdapterDTO;
21
import eu.etaxonomy.vaadin.mvp.AbstractPopupEditor;
22
import eu.etaxonomy.vaadin.util.PropertyIdPath;
23

  
24
/**
25
 * @author a.kohlbecker
26
 * @since Oct 29, 2018
27
 *
28
 */
29
public class EditorActionContextFormatter {
30

  
31
    private static final String NEW = "New";
32

  
33
    private static final String EDIT = "Edit";
34

  
35
    public String format(EditorActionContext cntxt, EditorActionContextFormat format) {
36

  
37
        String className = null;
38
        String targetInfo = null;
39
        String createOrNew = null;
40

  
41
        Object parentEntity = cntxt.getParentEntity();
42

  
43
        if (parentEntity != null) {
44
            if (parentEntity instanceof TypedEntityReference) {
45
                className = ((TypedEntityReference) cntxt.getParentEntity()).getType().getSimpleName();
46
                createOrNew = EDIT;
47
            } else if (CdmEntityAdapterDTO.class.isAssignableFrom(parentEntity.getClass())) {
48
                CdmBase cdmEntity = ((CdmEntityAdapterDTO) parentEntity).cdmEntity();
49
                className = cdmEntity.getClass().getSimpleName();
50
                createOrNew = cdmEntity.isPersited() ? EDIT : NEW;
51
            } else if (CdmBase.class.isAssignableFrom(parentEntity.getClass())) {
52
                CdmBase cdmEntity = ((CdmBase) parentEntity);
53
                className = cdmEntity.getClass().getSimpleName();
54
                createOrNew = cdmEntity.isPersited() ? EDIT : NEW;
55
            } else {
56
                className = parentEntity.getClass().getSimpleName();
57
                // can not decide for createOrNew in this case
58
            }
59
        } else {
60
            className += "[NULL_CLASS]";
61
        }
62

  
63
        if (format.doTargetInfo && cntxt.getParentView() != null && AbstractPopupEditor.class.isAssignableFrom(cntxt.getParentView().getClass())) {
64
            // the top element is the cntxt istself!! we need to dig one step deeper to get the previous popup editor
65
            // TODO chaining the EditorActionContext would ease find the contexts of parent editors
66
            Stack<EditorActionContext> ctxtStack = ((AbstractPopupEditor)cntxt.getParentView()).getEditorActionContext();
67
            int parentPopupPos = ctxtStack.size() - 2;
68
            if(parentPopupPos > -1){
69
                EditorActionContext parentCtx = ctxtStack.get(parentPopupPos);
70
                if(format.targetInfoType.equals(TargetInfoType.PROPERTIES)){
71
                    PropertyIdPath propertyIdPath = parentCtx.getTargetPropertyIdPath();
72
                    if (propertyIdPath != null) {
73
                        targetInfo = propertyIdPath.toString();
74
                    }
75
                } else {
76
                    // TargetInfoType.FIELD_CAPTION
77
                    if(parentCtx.getTargetField() != null){
78
                        Component captionComponent = parentCtx.getTargetField();
79
                        while(captionComponent != null){
80
                            targetInfo = captionComponent.getCaption();
81
                            if(targetInfo != null){
82
                                break;
83
                            }
84
                            captionComponent = captionComponent.getParent();
85
                        }
86
                    }
87
                }
88
            }
89
        }
90

  
91
        // create output
92
        String markup = "";
93

  
94
        if (format.doCreateOrNew && createOrNew != null) {
95
            markup += "<" + format.tagName + " class=\"operation " + format.classAttributes + "\">" + createOrNew + "</" + format.tagName + ">";
96
        }
97

  
98
        if (format.doTargetInfo) {
99
            if(targetInfo == null && format.classNameForMissingTargetData && className != null){
100
                targetInfo = className;
101
            }
102
            if(targetInfo != null){
103
                if(!markup.isEmpty()){
104
                    markup += " ";
105
                    targetInfo = normalizeTargetInfo(targetInfo);
106
                }
107
                markup += "<" + format.tagName + " class=\"target " + format.classAttributes + "\">" + targetInfo + "</" + format.tagName + ">";
108
            }
109
        }
110
        return markup;
111
    }
112

  
113
    /**
114
     * @param targetInfo
115
     * @return
116
     */
117
    public String normalizeTargetInfo(String targetInfo) {
118
        targetInfo = StringUtils.join(StringUtils.splitByCharacterTypeCamelCase(targetInfo), " ");
119
        targetInfo = targetInfo.toLowerCase();
120
        return targetInfo;
121
    }
122

  
123
}
src/main/java/eu/etaxonomy/cdm/vaadin/view/name/TaxonNamePopupEditor.java
555 555
            updateAuthorshipFields();
556 556
        }
557 557
        if(isModeEnabled(TaxonNamePopupEditorMode.NOMENCLATURALREFERENCE_SECTION_EDITING_ONLY) && getBean().getNomenclaturalReference() != null) {
558
            nomReferenceCombobox.setCaption("Selection limited to nomenclatural reference and parts of it.");
558
            nomReferenceCombobox.setDescription("Selection limited to nomenclatural reference and parts of it.");
559 559
        }
560 560
        if(isModeEnabled(TaxonNamePopupEditorMode.REQUIRE_NOMENCLATURALREFERENCE)) {
561 561
            if(combinationAuthorshipField.getValue() == null){
src/main/java/eu/etaxonomy/cdm/vaadin/view/registration/RegistrationWorkingsetPresenter.java
72 72
import eu.etaxonomy.cdm.vaadin.component.registration.RegistrationItem;
73 73
import eu.etaxonomy.cdm.vaadin.component.registration.RegistrationStatusFieldInstantiator;
74 74
import eu.etaxonomy.cdm.vaadin.component.registration.RegistrationStatusSelect;
75
import eu.etaxonomy.cdm.vaadin.event.AbstractEditorAction.EditorActionContext;
75
import eu.etaxonomy.cdm.vaadin.event.EditorActionContext;
76 76
import eu.etaxonomy.cdm.vaadin.event.EditorActionTypeFilter;
77 77
import eu.etaxonomy.cdm.vaadin.event.EntityChangeEvent;
78 78
import eu.etaxonomy.cdm.vaadin.event.ReferenceEditorAction;
......
428 428
        }
429 429

  
430 430
        TaxonNamePopupEditor popup = openPopupEditor(TaxonNamePopupEditor.class, event);
431
        popup.setParentEditorActionContext(event.getContext());
431
        popup.setParentEditorActionContext(event.getContext(), event.getTarget());
432 432
        popup.withDeleteButton(true);
433 433
        TaxonNamePopupEditorConfig.configureForNomenclaturalAct(popup);
434 434
        popup.loadInEditor(event.getEntityUuid());
......
451 451
        if(newNameForRegistrationPopupEditor == null){
452 452
            TaxonNamePopupEditor popup = openPopupEditor(TaxonNamePopupEditor.class, event);
453 453
            newNameForRegistrationPopupEditor = popup;
454
            popup.setParentEditorActionContext(event.getContext());
454
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
455 455
            popup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE,CRUD.DELETE));
456 456
            popup.withDeleteButton(true);
457 457
            popup.setCdmEntityInstantiator(new BeanInstantiator<TaxonName>() {
......
581 581

  
582 582
        if(event.getWorkingSetType() == TypeDesignationWorkingSetType.SPECIMEN_TYPE_DESIGNATION_WORKINGSET ){
583 583
            SpecimenTypeDesignationWorkingsetPopupEditor popup = openPopupEditor(SpecimenTypeDesignationWorkingsetPopupEditor.class, event);
584
            popup.setParentEditorActionContext(event.getContext());
584
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
585 585
            popup.withDeleteButton(true);
586 586
            popup.loadInEditor(new TypeDesignationWorkingsetEditorIdSet(event.getRegistrationUuid(), event.getBaseEntityRef()));
587 587
            if(event.hasSource()){
......
590 590
            }
591 591
        } else {
592 592
            NameTypeDesignationPopupEditor popup = openPopupEditor(NameTypeDesignationPopupEditor.class, event);
593
            popup.setParentEditorActionContext(event.getContext());
593
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
594 594
            popup.withDeleteButton(true);
595 595
            popup.loadInEditor(new TypeDesignationWorkingsetEditorIdSet(event.getRegistrationUuid(), event.getBaseEntityRef()));
596 596

  
......
614 614

  
615 615
        if(event.getWorkingSetType() == TypeDesignationWorkingSetType.SPECIMEN_TYPE_DESIGNATION_WORKINGSET){
616 616
            SpecimenTypeDesignationWorkingsetPopupEditor popup = openPopupEditor(SpecimenTypeDesignationWorkingsetPopupEditor.class, event);
617
            popup.setParentEditorActionContext(event.getContext());
617
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
618 618
            TypeDesignationWorkingsetEditorIdSet identifierSet;
619 619
            UUID typifiedNameUuid;
620 620

  
......
642 642
            }
643 643
        } else {
644 644
            NameTypeDesignationPopupEditor popup = openPopupEditor(NameTypeDesignationPopupEditor.class, event);
645
            popup.setParentEditorActionContext(event.getContext());
645
            popup.setParentEditorActionContext(event.getContext(), event.getTarget());
646 646
            popup.withDeleteButton(true);
647 647
            popup.grantToCurrentUser(EnumSet.of(CRUD.UPDATE, CRUD.DELETE));
648 648
            RegistrationDTO regDto = workingset.getRegistrationDTO(event.getRegistrationUuid()).get();
src/main/java/eu/etaxonomy/cdm/vaadin/view/registration/RegistrationWorksetViewBean.java
66 66
import eu.etaxonomy.cdm.vaadin.component.registration.RegistrationStatusFieldInstantiator;
67 67
import eu.etaxonomy.cdm.vaadin.component.registration.RegistrationStatusLabel;
68 68
import eu.etaxonomy.cdm.vaadin.component.registration.RegistrationStyles;
69
import eu.etaxonomy.cdm.vaadin.event.AbstractEditorAction.EditorActionContext;
69
import eu.etaxonomy.cdm.vaadin.event.EditorActionContext;
70 70
import eu.etaxonomy.cdm.vaadin.event.RegistrationEditorAction;
71 71
import eu.etaxonomy.cdm.vaadin.event.ShowDetailsEvent;
72 72
import eu.etaxonomy.cdm.vaadin.event.TaxonNameEditorAction;
src/main/java/eu/etaxonomy/vaadin/mvp/AbstractPopupEditor.java
29 29
import com.vaadin.server.AbstractErrorMessage.ContentMode;
30 30
import com.vaadin.server.ErrorMessage.ErrorLevel;
31 31
import com.vaadin.server.FontAwesome;
32
import com.vaadin.server.GenericFontIcon;
32 33
import com.vaadin.server.UserError;
33 34
import com.vaadin.shared.ui.MarginInfo;
34 35
import com.vaadin.ui.AbstractComponentContainer;
......
58 59

  
59 60
import eu.etaxonomy.cdm.database.PermissionDeniedException;
60 61
import eu.etaxonomy.cdm.vaadin.component.TextFieldNFix;
61
import eu.etaxonomy.cdm.vaadin.event.AbstractEditorAction;
62
import eu.etaxonomy.cdm.vaadin.event.AbstractEditorAction.EditorActionContext;
62
import eu.etaxonomy.cdm.vaadin.event.EditorActionContext;
63
import eu.etaxonomy.cdm.vaadin.event.EditorActionContextFormat;
64
import eu.etaxonomy.cdm.vaadin.event.EditorActionContextFormatter;
63 65
import eu.etaxonomy.vaadin.component.NestedFieldGroup;
64 66
import eu.etaxonomy.vaadin.component.SwitchableTextField;
65 67
import eu.etaxonomy.vaadin.event.FieldReplaceEvent;
......
106 108

  
107 109
    private CssLayout toolBarButtonGroup = new CssLayout();
108 110

  
111
    private Label contextBreadcrumbsLabel = new Label();
112

  
109 113
    private Label statusMessageLabel = new Label();
110 114

  
111 115
    Set<String> statusMessages = new HashSet<>();
......
139 143

  
140 144
        toolBar.addStyleName(ValoTheme.WINDOW_TOP_TOOLBAR);
141 145
        toolBar.setWidth(100, Unit.PERCENTAGE);
146
        contextBreadcrumbsLabel.setId("context-breadcrumbs");
147
        contextBreadcrumbsLabel.setWidthUndefined();
148
        contextBreadcrumbsLabel.setContentMode(com.vaadin.shared.ui.label.ContentMode.HTML);
149
        toolBar.addComponent(contextBreadcrumbsLabel);
142 150
        toolBarButtonGroup.addStyleName(ValoTheme.LAYOUT_COMPONENT_GROUP);
143 151
        toolBarButtonGroup.setWidthUndefined();
144 152
        toolBar.addComponent(toolBarButtonGroup);
......
718 726
        statusMessageLabel.addStyleName(ValoTheme.LABEL_COLORED);
719 727
    }
720 728

  
729
    private void updateContextBreadcrumbs() {
730

  
731
        List<EditorActionContext> contextInfo = new ArrayList<>(getEditorActionContext());
732
        String breadcrumbs = "";
733
        EditorActionContextFormatter formatter = new EditorActionContextFormatter();
734

  
735
        GenericFontIcon operationPrefixIcon = new GenericFontIcon("IcoMoon", 0xe902);
736
        GenericFontIcon operationSuffxIcon = new GenericFontIcon("IcoMoon", 0xe901);
737

  
738
        int cnt = 0;
739
        for(EditorActionContext cntxt : contextInfo){
740
            cnt++;
741
            boolean isLast = cnt == contextInfo.size();
742
            boolean isFirst = cnt == 1;
743

  
744
            boolean doClass = false; // will be removed in future
745
            boolean classNameForMissingPropertyPath = true; // !doClass;
746
            boolean doProperties = true;
747
            boolean doCreateOrNew = !isFirst;
748
            String contextmarkup = formatter.format(
749
                    cntxt,
750
                    new EditorActionContextFormat(doClass, doProperties, classNameForMissingPropertyPath, doCreateOrNew,
751
                            EditorActionContextFormat.TargetInfoType.FIELD_CAPTION, (isLast ? "active" : ""))
752
                    );
753
//            if(!isLast){
754
//                contextmarkup += " " + FontAwesome.ANGLE_RIGHT.getHtml() + " ";
755
//            }
756
            if(isLast){
757
                contextmarkup = "<li><span class=\"crumb active\">" + contextmarkup + "</span></li>";
758
            } else {
759
                contextmarkup = "<li><span class=\"crumb\">" + contextmarkup + "</span></li>";
760
            }
761
            breadcrumbs += contextmarkup;
762
        }
763
        contextBreadcrumbsLabel.setValue("<ul class=\"breadcrumbs\">" + breadcrumbs + "</ul>");
764
    }
765

  
721 766
    // ------------------------ data binding ------------------------ //
722 767

  
723 768
    protected void bindDesign(Component component) {
......
733 778
        fieldGroup.setItemDataSource(beanToEdit);
734 779
        afterItemDataSourceSet();
735 780
        getPresenter().adaptToUserPermission(beanToEdit);
781
        updateContextBreadcrumbs();
736 782
        isBeanLoaded = true;
737 783
    }
738 784

  
......
817 863
            if(getBean() == null){
818 864
                throw new RuntimeException("getContext() is only possible after the bean is loaded");
819 865
            }
820
            context.push(new AbstractEditorAction.EditorActionContext(getBean(), this));
866
            context.push(new EditorActionContext(getBean(), this));
821 867
            isContextUpdated = true;
822 868
        }
823 869
        return context;
......
828 874
     *
829 875
     * @param context the context to set
830 876
     */
831
    public void setParentEditorActionContext(Stack<EditorActionContext> context) {
877
    public void setParentEditorActionContext(Stack<EditorActionContext> context, Field<?> targetField) {
832 878
        if(context != null){
833 879
            this.context.addAll(context);
834 880
        }
881
        if(targetField != null){
882
            this.context.get(context.size() - 1).setTargetField(targetField);
883
        }
835 884
    }
836 885

  
837 886
    protected AbstractField<String> replaceComponent(String propertyId, AbstractField<String> oldField, AbstractField<String> newField, int column1, int row1, int column2,
src/main/java/eu/etaxonomy/vaadin/ui/navigation/NavigationManagerBean.java
23 23
import com.vaadin.ui.UI;
24 24
import com.vaadin.ui.Window;
25 25

  
26
import eu.etaxonomy.cdm.vaadin.event.AbstractEditorAction.EditorActionContext;
26
import eu.etaxonomy.cdm.vaadin.event.EditorActionContext;
27 27
import eu.etaxonomy.vaadin.mvp.AbstractEditorPresenter;
28 28
import eu.etaxonomy.vaadin.mvp.AbstractPopupEditor;
29 29
import eu.etaxonomy.vaadin.mvp.ApplicationView;
......
158 158
	        if(parentView instanceof AbstractPopupEditor){
159 159
	            // retain the chain of EditorActionContexts when starting a new pupupEditor
160 160
	            Stack<EditorActionContext> parentEditorActionContext = ((AbstractPopupEditor)parentView).getEditorActionContext();
161
	            ((AbstractPopupEditor)popupView).setParentEditorActionContext(parentEditorActionContext);
161
	            ((AbstractPopupEditor)popupView).setParentEditorActionContext(parentEditorActionContext, targetField);
162 162
	        }
163 163
	    }
164 164

  
src/main/webapp/VAADIN/themes/edit-valo/edit-valo.scss
472 472
        }
473 473
    }
474 474
    
475
    #context-breadcrumbs .breadcrumbs {
476
      // for an explanation of how the CSS Triangles to work 
477
      // see https://css-tricks.com/triangle-breadcrumbs/
478
    
479
      $crumb-background-color: $v-app-background-color;
480
      $crumb-active-background-color: #3a6972; //TODO calculate using active-color and $v-background-color or $v-app-background-color
481
      $crumb-border-color: $v-textfield-background-color--readonly;
482
      $crumb-height: 10px; 
483
      $triangle-width: 10px; 
484
      
485
      $crumb-border: valo-border($color: $crumb-border-color);
486
      
487
      list-style: none; 
488
      overflow: hidden;
489
      margin: 0; 
490
      padding: 0;
491
      line-height: $crumb-height;
492
      border-radius: $v-border-radius;
493
      border: $crumb-border;
494
      li {
495
          float: left;
496
          span.crumb {
497
            padding: 10px 10px 10px 20px;
498
            background-color: $crumb-background-color;
499
            position: relative;
500
            display: block;
501
            float: left;
502
            &::before {
503
                  content: " "; 
504
                  display: block;
505
                  width: 0; 
506
                  height: 0;
507
                  border-left: $crumb-border;
508
                  border-left-width: $triangle-width;
509
                  border-top: $crumb-height*2 solid transparent;
510
                  border-bottom: $crumb-height*2 solid transparent;
511
                  position: absolute;
512
                  top: 50%;
513
                  margin-top: -$crumb-height*2;
514
                  margin-left: 1px;
515
                  left: 100%;
516
                  z-index: 1; 
517
              }
518
              &::after {
519
                  content: " "; 
520
                  display: block;
521
                  width: 0; 
522
                  height: 0;
523
                  border-left: $triangle-width solid $crumb-background-color;
524
                  border-top: $crumb-height*2 solid transparent;
525
                  border-bottom: $crumb-height*2 solid transparent;
526
                  border-right: none;
527
                  position: absolute;
528
                  top: 50%;
529
                  margin-top: -$crumb-height*2;
530
                  left: 100%;
531
                  z-index: 2; 
532
              }
533
          }
534
          &::first-child span.crumb {
535
            padding-left: 10px;
536
          }
537
          span.active {
538
              background-color: $crumb-active-background-color;
539
          }
540
       }
541
       
542
    }
543
    
475 544
    // ---------- ---------- //
476 545

  
477 546
    .v-slot-message-item {

Also available in: Unified diff