mirror of
				https://github.com/TriliumNext/Notes.git
				synced 2025-11-04 15:11:31 +08:00 
			
		
		
		
	new CollapsibleSectionContainer WIP
This commit is contained in:
		
							parent
							
								
									435200ec5a
								
							
						
					
					
						commit
						2c028f7c45
					
				
							
								
								
									
										6
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										6
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							@ -4549,9 +4549,9 @@
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "jasmine": {
 | 
			
		||||
      "version": "3.6.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-3.6.2.tgz",
 | 
			
		||||
      "integrity": "sha512-Uc0o2MRnC8TS1MjDrB8jE1umKEo2mflzGvdg0Ncs+yuLtOJ+uz/Wz8VmGsNGtuASr8+E0LDgPkOpvdoC76m5WQ==",
 | 
			
		||||
      "version": "3.6.3",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-3.6.3.tgz",
 | 
			
		||||
      "integrity": "sha512-Th91zHsbsALWjDUIiU5d/W5zaYQsZFMPTdeNmi8GivZPmAaUAK8MblSG3yQI4VMGC/abF2us7ex60NH1AAIMTA==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "glob": "^7.1.6",
 | 
			
		||||
 | 
			
		||||
@ -81,7 +81,7 @@
 | 
			
		||||
    "electron-packager": "15.1.0",
 | 
			
		||||
    "electron-rebuild": "2.3.2",
 | 
			
		||||
    "esm": "3.2.25",
 | 
			
		||||
    "jasmine": "3.6.2",
 | 
			
		||||
    "jasmine": "3.6.3",
 | 
			
		||||
    "jsdoc": "3.6.6",
 | 
			
		||||
    "lorem-ipsum": "2.0.3",
 | 
			
		||||
    "rcedit": "2.2.0",
 | 
			
		||||
 | 
			
		||||
@ -9,7 +9,7 @@ import RunScriptButtonsWidget from "../widgets/run_script_buttons.js";
 | 
			
		||||
import NoteTypeWidget from "../widgets/note_type.js";
 | 
			
		||||
import NoteActionsWidget from "../widgets/note_actions.js";
 | 
			
		||||
import NoteDetailWidget from "../widgets/note_detail.js";
 | 
			
		||||
import AttributeListWidget from "../widgets/attribute_list.js";
 | 
			
		||||
import OwnedAttributeListWidget from "../widgets/owned_attribute_list.js";
 | 
			
		||||
 | 
			
		||||
export default class DesktopExtraWindowLayout {
 | 
			
		||||
    constructor(customWidgets) {
 | 
			
		||||
@ -39,7 +39,7 @@ export default class DesktopExtraWindowLayout {
 | 
			
		||||
                        .child(new NoteTypeWidget().hideInZenMode())
 | 
			
		||||
                        .child(new NoteActionsWidget().hideInZenMode())
 | 
			
		||||
                    )
 | 
			
		||||
                    .child(new TabCachingWidget(() => new AttributeListWidget()))
 | 
			
		||||
                    .child(new TabCachingWidget(() => new OwnedAttributeListWidget()))
 | 
			
		||||
                    .child(new TabCachingWidget(() => new NoteDetailWidget()))
 | 
			
		||||
                    .child(...this.customWidgets.get('center-pane'))
 | 
			
		||||
                )
 | 
			
		||||
 | 
			
		||||
@ -11,7 +11,7 @@ import NoteTreeWidget from "../widgets/note_tree.js";
 | 
			
		||||
import TabCachingWidget from "../widgets/tab_caching_widget.js";
 | 
			
		||||
import NotePathsWidget from "../widgets/note_paths.js";
 | 
			
		||||
import NoteTitleWidget from "../widgets/note_title.js";
 | 
			
		||||
import AttributeListWidget from "../widgets/attribute_list.js";
 | 
			
		||||
import OwnedAttributeListWidget from "../widgets/owned_attribute_list.js";
 | 
			
		||||
import RunScriptButtonsWidget from "../widgets/run_script_buttons.js";
 | 
			
		||||
import NoteTypeWidget from "../widgets/note_type.js";
 | 
			
		||||
import NoteActionsWidget from "../widgets/note_actions.js";
 | 
			
		||||
@ -26,6 +26,7 @@ import SidePaneToggles from "../widgets/side_pane_toggles.js";
 | 
			
		||||
import EditedNotesWidget from "../widgets/collapsible_widgets/edited_notes.js";
 | 
			
		||||
import CollapsibleSectionContainer from "../widgets/collapsible_section_container.js";
 | 
			
		||||
import PromotedAttributesWidget from "../widgets/promoted_attributes.js";
 | 
			
		||||
import InheritedAttributesWidget from "../widgets/inherited_attribute_list.js";
 | 
			
		||||
 | 
			
		||||
const RIGHT_PANE_CSS = `
 | 
			
		||||
<style>
 | 
			
		||||
@ -158,7 +159,8 @@ export default class DesktopMainWindowLayout {
 | 
			
		||||
                    .child(
 | 
			
		||||
                        new TabCachingWidget(() => new CollapsibleSectionContainer()
 | 
			
		||||
                            .child(new PromotedAttributesWidget())
 | 
			
		||||
                            .child(new AttributeListWidget())
 | 
			
		||||
                            .child(new OwnedAttributeListWidget())
 | 
			
		||||
                            .child(new InheritedAttributesWidget())
 | 
			
		||||
                        )
 | 
			
		||||
                    )
 | 
			
		||||
                    .child(new TabCachingWidget(() => new NoteDetailWidget()))
 | 
			
		||||
 | 
			
		||||
@ -1,30 +0,0 @@
 | 
			
		||||
import BasicWidget from "./basic_widget.js";
 | 
			
		||||
 | 
			
		||||
export default class AbstractContainer extends BasicWidget {
 | 
			
		||||
    constructor() {
 | 
			
		||||
        super();
 | 
			
		||||
 | 
			
		||||
        this.children = [];
 | 
			
		||||
 | 
			
		||||
        this.positionCounter = 10;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    child(...components) {
 | 
			
		||||
        if (!components) {
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        super.child(...components);
 | 
			
		||||
 | 
			
		||||
        for (const component of components) {
 | 
			
		||||
            if (!component.position) {
 | 
			
		||||
                component.position = this.positionCounter;
 | 
			
		||||
                this.positionCounter += 10;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.children.sort((a, b) => a.position - b.position < 0 ? -1 : 1);
 | 
			
		||||
 | 
			
		||||
        return this;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -17,7 +17,7 @@ const HELP_TEXT = `
 | 
			
		||||
<p>Alternatively you can add label and relation using the <code>+</code> button on the right side.</p>`;
 | 
			
		||||
 | 
			
		||||
const TPL = `
 | 
			
		||||
<div style="position: relative">
 | 
			
		||||
<div style="position: relative; padding-top: 10px; padding-bottom: 10px">
 | 
			
		||||
    <style>
 | 
			
		||||
    .attribute-list-editor {
 | 
			
		||||
        border: 0 !important;
 | 
			
		||||
 | 
			
		||||
@ -1,273 +0,0 @@
 | 
			
		||||
import TabAwareWidget from "./tab_aware_widget.js";
 | 
			
		||||
import AttributeDetailWidget from "./attribute_detail.js";
 | 
			
		||||
import attributeRenderer from "../services/attribute_renderer.js";
 | 
			
		||||
import AttributeEditorWidget from "./attribute_editor.js";
 | 
			
		||||
import options from '../services/options.js';
 | 
			
		||||
 | 
			
		||||
const TPL = `
 | 
			
		||||
<div class="attribute-list">
 | 
			
		||||
    <style>
 | 
			
		||||
        .attribute-list {
 | 
			
		||||
            margin-left: 7px;
 | 
			
		||||
            margin-right: 7px;
 | 
			
		||||
            position: relative;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        .inherited-attributes-wrapper {
 | 
			
		||||
            color: var(--muted-text-color);
 | 
			
		||||
            max-height: 200px;
 | 
			
		||||
            overflow: auto;
 | 
			
		||||
            padding-bottom: 5px;
 | 
			
		||||
            padding-left: 7px;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        .attribute-list-editor p {
 | 
			
		||||
            margin: 0 !important;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        .attribute-list.error .attribute-list-editor {
 | 
			
		||||
            border-color: red !important;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        .area-expander {
 | 
			
		||||
            display: flex; 
 | 
			
		||||
            flex-direction: row; 
 | 
			
		||||
            color: var(--muted-text-color); 
 | 
			
		||||
            font-size: 90%;
 | 
			
		||||
            margin: 3px 0 3px 0; 
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        .attribute-list hr {
 | 
			
		||||
            height: 1px;
 | 
			
		||||
            border-color: var(--main-border-color);
 | 
			
		||||
            position: relative;
 | 
			
		||||
            top: 4px;
 | 
			
		||||
            margin-top: 5px;
 | 
			
		||||
            margin-bottom: 0;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        .area-expander-text {
 | 
			
		||||
            padding-left: 20px;
 | 
			
		||||
            padding-right: 20px;
 | 
			
		||||
            white-space: nowrap;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        .area-expander:hover {
 | 
			
		||||
            cursor: pointer;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        .area-expander:hover hr {
 | 
			
		||||
            border-color: var(--main-text-color);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        .area-expander:hover .area-expander-text {
 | 
			
		||||
            color: var(--main-text-color);
 | 
			
		||||
        }
 | 
			
		||||
    </style>
 | 
			
		||||
    
 | 
			
		||||
    <div class="area-expander attr-promoted-expander">
 | 
			
		||||
        <hr class="w-100">
 | 
			
		||||
        
 | 
			
		||||
        <div class="area-expander-text">Promoted attributes</div>
 | 
			
		||||
        
 | 
			
		||||
        <hr class="w-100">
 | 
			
		||||
    </div>
 | 
			
		||||
    
 | 
			
		||||
    <div class="all-attr-wrapper">
 | 
			
		||||
        <div class="promoted-attributes-placeholder"></div>
 | 
			
		||||
    
 | 
			
		||||
        <div class="area-expander attr-owned-and-inherited-expander">
 | 
			
		||||
            <hr class="w-100">
 | 
			
		||||
            
 | 
			
		||||
            <div class="area-expander-text"></div>
 | 
			
		||||
            
 | 
			
		||||
            <hr class="w-100">
 | 
			
		||||
        </div>
 | 
			
		||||
        
 | 
			
		||||
        <div class="owned-and-inherited-wrapper">
 | 
			
		||||
            <div class="attr-editor-placeholder"></div>
 | 
			
		||||
            
 | 
			
		||||
            <hr class="w-100 attr-inherited-empty-expander" style="margin-bottom: 10px;">
 | 
			
		||||
            
 | 
			
		||||
            <div class="area-expander attr-inherited-expander">
 | 
			
		||||
                <hr class="w-100">
 | 
			
		||||
                
 | 
			
		||||
                <div class="area-expander-text"></div>
 | 
			
		||||
                
 | 
			
		||||
                <hr class="w-100">
 | 
			
		||||
            </div>
 | 
			
		||||
            
 | 
			
		||||
            <div class="inherited-attributes-wrapper"></div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
`;
 | 
			
		||||
 | 
			
		||||
export default class AttributeListWidget extends TabAwareWidget {
 | 
			
		||||
    constructor() {
 | 
			
		||||
        super();
 | 
			
		||||
 | 
			
		||||
        this.attributeDetailWidget = new AttributeDetailWidget().setParent(this);
 | 
			
		||||
        this.attributeEditorWidget = new AttributeEditorWidget(this.attributeDetailWidget).setParent(this);
 | 
			
		||||
 | 
			
		||||
        this.child(this.attributeEditorWidget, this.attributeDetailWidget);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    renderTitle() {
 | 
			
		||||
        this.$title = $('<div>').text('Attribute list');
 | 
			
		||||
        return this.$title;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    doRender() {
 | 
			
		||||
        this.$widget = $(TPL);
 | 
			
		||||
        this.overflowing();
 | 
			
		||||
 | 
			
		||||
        this.$promotedExpander = this.$widget.find('.attr-promoted-expander');
 | 
			
		||||
        this.$allAttrWrapper = this.$widget.find('.all-attr-wrapper');
 | 
			
		||||
 | 
			
		||||
        this.$promotedExpander.on('click', async () => {
 | 
			
		||||
            const collapse = this.$allAttrWrapper.is(":visible");
 | 
			
		||||
 | 
			
		||||
            await options.save('promotedAttributesExpanded', !collapse);
 | 
			
		||||
 | 
			
		||||
            this.triggerEvent(`promotedAttributesCollapsedStateChanged`, {collapse});
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this.$ownedAndInheritedWrapper = this.$widget.find('.owned-and-inherited-wrapper');
 | 
			
		||||
 | 
			
		||||
        this.$ownedExpander = this.$widget.find('.attr-owned-and-inherited-expander');
 | 
			
		||||
        this.$ownedExpander.on('click', async () => {
 | 
			
		||||
            const collapse = this.$ownedAndInheritedWrapper.is(":visible");
 | 
			
		||||
 | 
			
		||||
            await options.save('attributeListExpanded', !collapse);
 | 
			
		||||
 | 
			
		||||
            this.triggerEvent(`attributeListCollapsedStateChanged`, {collapse});
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this.$ownedExpanderText = this.$ownedExpander.find('.area-expander-text');
 | 
			
		||||
 | 
			
		||||
        this.$inheritedAttributesWrapper = this.$widget.find('.inherited-attributes-wrapper');
 | 
			
		||||
 | 
			
		||||
        this.$inheritedExpander = this.$widget.find('.attr-inherited-expander');
 | 
			
		||||
        this.$inheritedExpander.on('click', () => {
 | 
			
		||||
            if (this.$inheritedAttributesWrapper.is(":visible")) {
 | 
			
		||||
                this.$inheritedAttributesWrapper.slideUp(200);
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                this.$inheritedAttributesWrapper.slideDown(200);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this.$inheritedExpanderText = this.$inheritedExpander.find('.area-expander-text');
 | 
			
		||||
 | 
			
		||||
        this.$inheritedEmptyExpander = this.$widget.find('.attr-inherited-empty-expander');
 | 
			
		||||
 | 
			
		||||
        this.$widget.find('.attr-editor-placeholder').replaceWith(this.attributeEditorWidget.render());
 | 
			
		||||
        this.$widget.append(this.attributeDetailWidget.render());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async refreshWithNote(note, updateOnly = false) {
 | 
			
		||||
        if (!updateOnly) {
 | 
			
		||||
            // const hasPromotedAttrs = this.promotedAttributesWidget.getPromotedDefinitionAttributes().length > 0;
 | 
			
		||||
            //
 | 
			
		||||
            // if (hasPromotedAttrs) {
 | 
			
		||||
            //     this.$promotedExpander.show();
 | 
			
		||||
            //     this.$allAttrWrapper.toggle(options.is('promotedAttributesExpanded'));
 | 
			
		||||
            //     this.$ownedAndInheritedWrapper.hide();
 | 
			
		||||
            //     this.$inheritedAttributesWrapper.hide();
 | 
			
		||||
            // } else {
 | 
			
		||||
            //     this.$promotedExpander.hide();
 | 
			
		||||
            //     this.$allAttrWrapper.show();
 | 
			
		||||
            //     this.$ownedAndInheritedWrapper.toggle(options.is('attributeListExpanded'));
 | 
			
		||||
            // }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const ownedAttributes = note.getOwnedAttributes().filter(attr => !attr.isAutoLink);
 | 
			
		||||
 | 
			
		||||
        this.$ownedExpanderText.text(ownedAttributes.length + ' owned ' + this.attrPlural(ownedAttributes.length));
 | 
			
		||||
 | 
			
		||||
        const inheritedAttributes = note.getAttributes().filter(attr => attr.noteId !== this.noteId);
 | 
			
		||||
 | 
			
		||||
        if (inheritedAttributes.length === 0) {
 | 
			
		||||
            this.$inheritedExpander.hide();
 | 
			
		||||
            this.$inheritedEmptyExpander.show();
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            this.$inheritedExpander.show();
 | 
			
		||||
            this.$inheritedEmptyExpander.hide();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.$inheritedExpanderText.text(inheritedAttributes.length + ' inherited ' + this.attrPlural(inheritedAttributes.length));
 | 
			
		||||
 | 
			
		||||
        this.$inheritedAttributesWrapper.empty();
 | 
			
		||||
 | 
			
		||||
        await this.renderInheritedAttributes(inheritedAttributes, this.$inheritedAttributesWrapper);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    attrPlural(number) {
 | 
			
		||||
        return 'attribute' + (number === 1 ? '' : 's');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async renderInheritedAttributes(attributes, $container) {
 | 
			
		||||
        for (const attribute of attributes) {
 | 
			
		||||
            const $attr = (await attributeRenderer.renderAttribute(attribute, false))
 | 
			
		||||
                .on('click', e => this.attributeDetailWidget.showAttributeDetail({
 | 
			
		||||
                    attribute: {
 | 
			
		||||
                        noteId: attribute.noteId,
 | 
			
		||||
                        type: attribute.type,
 | 
			
		||||
                        name: attribute.name,
 | 
			
		||||
                        value: attribute.value
 | 
			
		||||
                    },
 | 
			
		||||
                    isOwned: false,
 | 
			
		||||
                    x: e.pageX,
 | 
			
		||||
                    y: e.pageY
 | 
			
		||||
                }));
 | 
			
		||||
 | 
			
		||||
            $container
 | 
			
		||||
                .append($attr)
 | 
			
		||||
                .append(" ");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async saveAttributesCommand() {
 | 
			
		||||
        await this.attributeEditorWidget.save();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async reloadAttributesCommand() {
 | 
			
		||||
        await this.attributeEditorWidget.refresh();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async updateAttributeListCommand({attributes}) {
 | 
			
		||||
        await this.attributeEditorWidget.updateAttributeList(attributes);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * This event is used to synchronize collapsed state of all the tab-cached widgets since they are all rendered
 | 
			
		||||
     * separately but should behave uniformly for the user.
 | 
			
		||||
     */
 | 
			
		||||
    attributeListCollapsedStateChangedEvent({collapse}) {
 | 
			
		||||
        if (collapse) {
 | 
			
		||||
            this.$ownedAndInheritedWrapper.slideUp(200);
 | 
			
		||||
        } else {
 | 
			
		||||
            this.$ownedAndInheritedWrapper.slideDown(200);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * This event is used to synchronize collapsed state of all the tab-cached widgets since they are all rendered
 | 
			
		||||
     * separately but should behave uniformly for the user.
 | 
			
		||||
     */
 | 
			
		||||
    promotedAttributesCollapsedStateChangedEvent({collapse}) {
 | 
			
		||||
        if (collapse) {
 | 
			
		||||
            this.$allAttrWrapper.slideUp(200);
 | 
			
		||||
        } else {
 | 
			
		||||
            this.$allAttrWrapper.slideDown(200);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    entitiesReloadedEvent({loadResults}) {
 | 
			
		||||
        if (loadResults.getAttributes(this.componentId).find(attr => attr.isAffecting(this.note))) {
 | 
			
		||||
            this.refreshWithNote(this.note, true);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,8 +1,12 @@
 | 
			
		||||
import AbstractContainer from "./abstract_container.js";
 | 
			
		||||
import TabAwareWidget from "./tab_aware_widget.js";
 | 
			
		||||
 | 
			
		||||
const TPL = `
 | 
			
		||||
<div class="section-container">
 | 
			
		||||
    <style>
 | 
			
		||||
    .section-container {
 | 
			
		||||
        margin-bottom: 10px;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    .section-title-container {
 | 
			
		||||
        display: flex;
 | 
			
		||||
        flex-direction: row;
 | 
			
		||||
@ -17,6 +21,11 @@ const TPL = `
 | 
			
		||||
        border-bottom: 1px solid var(--main-border-color); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    .section-title.active {
 | 
			
		||||
        color: var(--main-text-color);
 | 
			
		||||
        border-bottom: 1px solid var(--main-text-color);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    .section-title:hover {
 | 
			
		||||
        cursor: pointer;
 | 
			
		||||
    }
 | 
			
		||||
@ -29,13 +38,49 @@ const TPL = `
 | 
			
		||||
        flex-shrink: 1;
 | 
			
		||||
        flex-grow: 1;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    .section-body {
 | 
			
		||||
        display: none;
 | 
			
		||||
        border-bottom: 1px solid var(--main-border-color);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    .section-body.active {
 | 
			
		||||
        display: block;
 | 
			
		||||
    }
 | 
			
		||||
    </style>
 | 
			
		||||
 | 
			
		||||
    <div class="section-title-container"></div>
 | 
			
		||||
    <div class="section-body-container"></div>
 | 
			
		||||
</div>`;
 | 
			
		||||
 | 
			
		||||
export default class CollapsibleSectionContainer extends AbstractContainer {
 | 
			
		||||
export default class CollapsibleSectionContainer extends TabAwareWidget {
 | 
			
		||||
    constructor() {
 | 
			
		||||
        super();
 | 
			
		||||
 | 
			
		||||
        this.children = [];
 | 
			
		||||
 | 
			
		||||
        this.positionCounter = 10;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    child(...components) {
 | 
			
		||||
        if (!components) {
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        super.child(...components);
 | 
			
		||||
 | 
			
		||||
        for (const component of components) {
 | 
			
		||||
            if (!component.position) {
 | 
			
		||||
                component.position = this.positionCounter;
 | 
			
		||||
                this.positionCounter += 10;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.children.sort((a, b) => a.position - b.position < 0 ? -1 : 1);
 | 
			
		||||
 | 
			
		||||
        return this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    doRender() {
 | 
			
		||||
        this.$widget = $(TPL);
 | 
			
		||||
        this.contentSized();
 | 
			
		||||
@ -47,7 +92,8 @@ export default class CollapsibleSectionContainer extends AbstractContainer {
 | 
			
		||||
 | 
			
		||||
        for (const widget of this.children) {
 | 
			
		||||
            this.$titleContainer.append(
 | 
			
		||||
                $('<div class="section-title">')
 | 
			
		||||
                $('<div class="section-title section-title-real">')
 | 
			
		||||
                    .attr('data-section-component-id', widget.componentId)
 | 
			
		||||
                    .append(widget.renderTitle())
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
@ -55,8 +101,27 @@ export default class CollapsibleSectionContainer extends AbstractContainer {
 | 
			
		||||
 | 
			
		||||
            this.$bodyContainer.append(
 | 
			
		||||
                $('<div class="section-body">')
 | 
			
		||||
                    .attr('data-section-component-id', widget.componentId)
 | 
			
		||||
                    .append(widget.render())
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.$titleContainer.on('click', '.section-title-real', e => {
 | 
			
		||||
            const $sectionTitle = $(e.target).closest('.section-title-real');
 | 
			
		||||
 | 
			
		||||
            const activate = !$sectionTitle.hasClass("active");
 | 
			
		||||
 | 
			
		||||
            this.$titleContainer.find('.section-title-real').removeClass("active");
 | 
			
		||||
            this.$bodyContainer.find('.section-body').removeClass("active");
 | 
			
		||||
 | 
			
		||||
            if (activate) {
 | 
			
		||||
                this.$titleContainer.find(`.section-title-real[data-section-component-id="${$sectionTitle.attr('data-section-component-id')}"]`).addClass("active");
 | 
			
		||||
                this.$bodyContainer.find(`.section-body[data-section-component-id="${$sectionTitle.attr('data-section-component-id')}"]`).addClass("active");
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async refreshWithNote(note) {
 | 
			
		||||
        this.$titleContainer.find('.section-title-real:first').trigger('click');
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
import AbstractContainer from "./abstract_container.js";
 | 
			
		||||
import BasicWidget from "./basic_widget.js";
 | 
			
		||||
 | 
			
		||||
export default class FlexContainer extends AbstractContainer {
 | 
			
		||||
export default class FlexContainer extends BasicWidget {
 | 
			
		||||
    constructor(direction) {
 | 
			
		||||
        super();
 | 
			
		||||
 | 
			
		||||
@ -9,6 +9,29 @@ export default class FlexContainer extends AbstractContainer {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.attrs.style = `display: flex; flex-direction: ${direction};`;
 | 
			
		||||
 | 
			
		||||
        this.children = [];
 | 
			
		||||
 | 
			
		||||
        this.positionCounter = 10;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    child(...components) {
 | 
			
		||||
        if (!components) {
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        super.child(...components);
 | 
			
		||||
 | 
			
		||||
        for (const component of components) {
 | 
			
		||||
            if (!component.position) {
 | 
			
		||||
                component.position = this.positionCounter;
 | 
			
		||||
                this.positionCounter += 10;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.children.sort((a, b) => a.position - b.position < 0 ? -1 : 1);
 | 
			
		||||
 | 
			
		||||
        return this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    doRender() {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										66
									
								
								src/public/app/widgets/inherited_attribute_list.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								src/public/app/widgets/inherited_attribute_list.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,66 @@
 | 
			
		||||
import TabAwareWidget from "./tab_aware_widget.js";
 | 
			
		||||
import AttributeDetailWidget from "./attribute_detail.js";
 | 
			
		||||
import attributeRenderer from "../services/attribute_renderer.js";
 | 
			
		||||
 | 
			
		||||
const TPL = `
 | 
			
		||||
<div class="inherited-attributes-widget">
 | 
			
		||||
    <style>
 | 
			
		||||
    .inherited-attributes-container {
 | 
			
		||||
        color: var(--muted-text-color);
 | 
			
		||||
        max-height: 200px;
 | 
			
		||||
        overflow: auto;
 | 
			
		||||
        padding-top: 10px;
 | 
			
		||||
        padding-bottom: 10px;
 | 
			
		||||
        padding-left: 7px;
 | 
			
		||||
    }
 | 
			
		||||
    </style>
 | 
			
		||||
 | 
			
		||||
    <div class="inherited-attributes-container"></div>
 | 
			
		||||
</div>`
 | 
			
		||||
 | 
			
		||||
export default class InheritedAttributesWidget extends TabAwareWidget {
 | 
			
		||||
    constructor() {
 | 
			
		||||
        super();
 | 
			
		||||
 | 
			
		||||
        this.attributeDetailWidget = new AttributeDetailWidget().setParent(this);
 | 
			
		||||
        this.child(this.attributeDetailWidget);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    renderTitle() {
 | 
			
		||||
        this.$title = $('<div>').text('Inherited attributes');
 | 
			
		||||
        return this.$title;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    doRender() {
 | 
			
		||||
        this.$widget = $(TPL);
 | 
			
		||||
        this.contentSized();
 | 
			
		||||
 | 
			
		||||
        this.$container = this.$widget.find('.inherited-attributes-container');
 | 
			
		||||
        this.$widget.append(this.attributeDetailWidget.render());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async refreshWithNote(note) {
 | 
			
		||||
        this.$container.empty();
 | 
			
		||||
 | 
			
		||||
        const inheritedAttributes = note.getAttributes().filter(attr => attr.noteId !== this.noteId);
 | 
			
		||||
 | 
			
		||||
        for (const attribute of inheritedAttributes) {
 | 
			
		||||
            const $attr = (await attributeRenderer.renderAttribute(attribute, false))
 | 
			
		||||
                .on('click', e => this.attributeDetailWidget.showAttributeDetail({
 | 
			
		||||
                    attribute: {
 | 
			
		||||
                        noteId: attribute.noteId,
 | 
			
		||||
                        type: attribute.type,
 | 
			
		||||
                        name: attribute.name,
 | 
			
		||||
                        value: attribute.value
 | 
			
		||||
                    },
 | 
			
		||||
                    isOwned: false,
 | 
			
		||||
                    x: e.pageX,
 | 
			
		||||
                    y: e.pageY
 | 
			
		||||
                }));
 | 
			
		||||
 | 
			
		||||
            this.$container
 | 
			
		||||
                .append($attr)
 | 
			
		||||
                .append(" ");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										63
									
								
								src/public/app/widgets/owned_attribute_list.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								src/public/app/widgets/owned_attribute_list.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,63 @@
 | 
			
		||||
import TabAwareWidget from "./tab_aware_widget.js";
 | 
			
		||||
import AttributeDetailWidget from "./attribute_detail.js";
 | 
			
		||||
import AttributeEditorWidget from "./attribute_editor.js";
 | 
			
		||||
 | 
			
		||||
const TPL = `
 | 
			
		||||
<div class="attribute-list">
 | 
			
		||||
    <style>
 | 
			
		||||
        .attribute-list {
 | 
			
		||||
            margin-left: 7px;
 | 
			
		||||
            margin-right: 7px;
 | 
			
		||||
            position: relative;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        .attribute-list-editor p {
 | 
			
		||||
            margin: 0 !important;
 | 
			
		||||
        }
 | 
			
		||||
    </style>
 | 
			
		||||
   
 | 
			
		||||
    <div class="attr-editor-placeholder"></div>
 | 
			
		||||
</div>
 | 
			
		||||
`;
 | 
			
		||||
 | 
			
		||||
export default class OwnedAttributeListWidget extends TabAwareWidget {
 | 
			
		||||
    constructor() {
 | 
			
		||||
        super();
 | 
			
		||||
 | 
			
		||||
        this.attributeDetailWidget = new AttributeDetailWidget().setParent(this);
 | 
			
		||||
        this.attributeEditorWidget = new AttributeEditorWidget(this.attributeDetailWidget).setParent(this);
 | 
			
		||||
 | 
			
		||||
        this.child(this.attributeEditorWidget, this.attributeDetailWidget);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    renderTitle() {
 | 
			
		||||
        this.$title = $('<div>').text('Owned attributes');
 | 
			
		||||
        return this.$title;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    doRender() {
 | 
			
		||||
        this.$widget = $(TPL);
 | 
			
		||||
        this.overflowing();
 | 
			
		||||
 | 
			
		||||
        this.$widget.find('.attr-editor-placeholder').replaceWith(this.attributeEditorWidget.render());
 | 
			
		||||
        this.$widget.append(this.attributeDetailWidget.render());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async saveAttributesCommand() {
 | 
			
		||||
        await this.attributeEditorWidget.save();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async reloadAttributesCommand() {
 | 
			
		||||
        await this.attributeEditorWidget.refresh();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async updateAttributeListCommand({attributes}) {
 | 
			
		||||
        await this.attributeEditorWidget.updateAttributeList(attributes);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    entitiesReloadedEvent({loadResults}) {
 | 
			
		||||
        if (loadResults.getAttributes(this.componentId).find(attr => attr.isAffecting(this.note))) {
 | 
			
		||||
            this.refreshWithNote(this.note, true);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user