attributes and children overview working again

This commit is contained in:
zadam 2019-05-04 22:44:25 +02:00
parent b21568806a
commit 7f0c92c56b
10 changed files with 300 additions and 310 deletions

2
package-lock.json generated
View File

@ -1,6 +1,6 @@
{
"name": "trilium",
"version": "0.31.4",
"version": "0.31.5",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

View File

@ -152,8 +152,6 @@ noteTooltipService.setupGlobalTooltip();
bundle.executeStartupBundles();
noteTypeService.init();
linkService.init();
noteAutocompleteService.init();

View File

@ -2,7 +2,6 @@ import noteDetailService from '../services/note_detail.js';
import server from '../services/server.js';
import infoService from "../services/info.js";
import treeUtils from "../services/tree_utils.js";
import attributeService from "../services/attributes.js";
import attributeAutocompleteService from "../services/attribute_autocomplete.js";
const $dialog = $("#attributes-dialog");
@ -168,7 +167,9 @@ function AttributesModel() {
infoService.showMessage("Attributes have been saved.");
attributeService.refreshAttributes();
const ctx = noteDetailService.getActiveContext();
ctx.attributes.refreshAttributes();
noteDetailService.reload();
};

View File

@ -4,308 +4,306 @@ import messagingService from "./messaging.js";
import treeUtils from "./tree_utils.js";
import noteAutocompleteService from "./note_autocomplete.js";
import linkService from "./link.js";
import noteDetailService from "./note_detail.js";
const $attributeList = $("#attribute-list");
const $attributeListInner = $("#attribute-list-inner");
const $promotedAttributesContainer = $("#note-detail-promoted-attributes");
const $savedIndicator = $(".saved-indicator");
let attributePromise;
function invalidateAttributes() {
attributePromise = null;
}
function reloadAttributes() {
attributePromise = server.get('notes/' + noteDetailService.getActiveNoteId() + '/attributes');
}
async function refreshAttributes() {
reloadAttributes();
await showAttributes();
}
async function getAttributes() {
if (!attributePromise) {
reloadAttributes();
class Attributes {
/**
* @param {NoteContext} ctx
*/
constructor(ctx) {
this.ctx = ctx;
this.$attributeList = ctx.$noteTabContent.find(".attribute-list");
this.$attributeListInner = ctx.$noteTabContent.find(".attribute-list-inner");
this.$promotedAttributesContainer = ctx.$noteTabContent.find(".note-detail-promoted-attributes");
this.$savedIndicator = ctx.$noteTabContent.find(".saved-indicator");
this.attributePromise = null;
}
return await attributePromise;
}
invalidateAttributes() {
this.attributePromise = null;
}
async function showAttributes() {
// FIXME tabs
return;
reloadAttributes() {
this.attributePromise = server.get(`notes/${this.ctx.note.noteId}/attributes`);
}
$promotedAttributesContainer.empty();
$attributeList.hide();
$attributeListInner.empty();
async refreshAttributes() {
this.reloadAttributes();
const note = noteDetailService.getActiveNote();
await this.showAttributes();
}
const attributes = await attributePromise;
const promoted = attributes.filter(attr =>
(attr.type === 'label-definition' || attr.type === 'relation-definition')
&& !attr.name.startsWith("child:")
&& attr.value.isPromoted);
const hidePromotedAttributes = attributes.some(attr => attr.type === 'label' && attr.name === 'hidePromotedAttributes');
if (promoted.length > 0 && !hidePromotedAttributes) {
const $tbody = $("<tbody>");
for (const definitionAttr of promoted) {
const definitionType = definitionAttr.type;
const valueType = definitionType.substr(0, definitionType.length - 11);
let valueAttrs = attributes.filter(el => el.name === definitionAttr.name && el.type === valueType);
if (valueAttrs.length === 0) {
valueAttrs.push({
attributeId: "",
type: valueType,
name: definitionAttr.name,
value: ""
});
}
if (definitionAttr.value.multiplicityType === 'singlevalue') {
valueAttrs = valueAttrs.slice(0, 1);
}
for (const valueAttr of valueAttrs) {
const $tr = await createPromotedAttributeRow(definitionAttr, valueAttr);
$tbody.append($tr);
}
async getAttributes() {
if (!this.attributePromise) {
this.reloadAttributes();
}
// we replace the whole content in one step so there can't be any race conditions
// (previously we saw promoted attributes doubling)
$promotedAttributesContainer.empty().append($tbody);
return await this.attributePromise;
}
else if (note.type !== 'relation-map') {
// display only "own" notes
const ownedAttributes = attributes.filter(attr => attr.noteId === note.noteId);
if (ownedAttributes.length > 0) {
for (const attribute of ownedAttributes) {
if (attribute.type === 'label') {
$attributeListInner.append(utils.formatLabel(attribute) + " ");
async showAttributes() {
this.$promotedAttributesContainer.empty();
this.$attributeList.hide();
this.$attributeListInner.empty();
const note = this.ctx.note;
const attributes = await this.getAttributes();
const promoted = attributes.filter(attr =>
(attr.type === 'label-definition' || attr.type === 'relation-definition')
&& !attr.name.startsWith("child:")
&& attr.value.isPromoted);
const hidePromotedAttributes = attributes.some(attr => attr.type === 'label' && attr.name === 'hidePromotedAttributes');
if (promoted.length > 0 && !hidePromotedAttributes) {
const $tbody = $("<tbody>");
for (const definitionAttr of promoted) {
const definitionType = definitionAttr.type;
const valueType = definitionType.substr(0, definitionType.length - 11);
let valueAttrs = attributes.filter(el => el.name === definitionAttr.name && el.type === valueType);
if (valueAttrs.length === 0) {
valueAttrs.push({
attributeId: "",
type: valueType,
name: definitionAttr.name,
value: ""
});
}
else if (attribute.type === 'relation') {
if (attribute.value) {
$attributeListInner.append('@' + attribute.name + "=");
$attributeListInner.append(await linkService.createNoteLink(attribute.value));
$attributeListInner.append(" ");
if (definitionAttr.value.multiplicityType === 'singlevalue') {
valueAttrs = valueAttrs.slice(0, 1);
}
for (const valueAttr of valueAttrs) {
const $tr = await this.createPromotedAttributeRow(definitionAttr, valueAttr);
$tbody.append($tr);
}
}
// we replace the whole content in one step so there can't be any race conditions
// (previously we saw promoted attributes doubling)
this.$promotedAttributesContainer.empty().append($tbody);
}
else if (note.type !== 'relation-map') {
// display only "own" notes
const ownedAttributes = attributes.filter(attr => attr.noteId === note.noteId);
if (ownedAttributes.length > 0) {
for (const attribute of ownedAttributes) {
if (attribute.type === 'label') {
this.$attributeListInner.append(utils.formatLabel(attribute) + " ");
}
else if (attribute.type === 'relation') {
if (attribute.value) {
this.$attributeListInner.append('@' + attribute.name + "=");
this.$attributeListInner.append(await linkService.createNoteLink(attribute.value));
this.$attributeListInner.append(" ");
}
else {
messagingService.logError(`Relation ${attribute.attributeId} has empty target`);
}
}
else if (attribute.type === 'label-definition' || attribute.type === 'relation-definition') {
this.$attributeListInner.append(attribute.name + " definition ");
}
else {
messagingService.logError(`Relation ${attribute.attributeId} has empty target`);
messagingService.logError("Unknown attr type: " + attribute.type);
}
}
else if (attribute.type === 'label-definition' || attribute.type === 'relation-definition') {
$attributeListInner.append(attribute.name + " definition ");
}
else {
messagingService.logError("Unknown attr type: " + attribute.type);
}
}
$attributeList.show();
this.$attributeList.show();
}
}
return attributes;
}
return attributes;
}
async createPromotedAttributeRow(definitionAttr, valueAttr) {
const definition = definitionAttr.value;
const $tr = $("<tr>");
const $labelCell = $("<th>").append(valueAttr.name);
const $input = $("<input>")
.prop("tabindex", definitionAttr.position)
.prop("attribute-id", valueAttr.isOwned ? valueAttr.attributeId : '') // if not owned, we'll force creation of a new attribute instead of updating the inherited one
.prop("attribute-type", valueAttr.type)
.prop("attribute-name", valueAttr.name)
.prop("value", valueAttr.value)
.addClass("form-control")
.addClass("promoted-attribute-input")
.change(event => this.promotedAttributeChanged(event));
async function createPromotedAttributeRow(definitionAttr, valueAttr) {
const definition = definitionAttr.value;
const $tr = $("<tr>");
const $labelCell = $("<th>").append(valueAttr.name);
const $input = $("<input>")
.prop("tabindex", definitionAttr.position)
.prop("attribute-id", valueAttr.isOwned ? valueAttr.attributeId : '') // if not owned, we'll force creation of a new attribute instead of updating the inherited one
.prop("attribute-type", valueAttr.type)
.prop("attribute-name", valueAttr.name)
.prop("value", valueAttr.value)
.addClass("form-control")
.addClass("promoted-attribute-input")
.change(promotedAttributeChanged);
const $inputCell = $("<td>").append($("<div>").addClass("input-group").append($input));
const $inputCell = $("<td>").append($("<div>").addClass("input-group").append($input));
const $actionCell = $("<td>");
const $multiplicityCell = $("<td>")
.addClass("multiplicity")
.attr("nowrap", true);
const $actionCell = $("<td>");
const $multiplicityCell = $("<td>")
.addClass("multiplicity")
.attr("nowrap", true);
$tr
.append($labelCell)
.append($inputCell)
.append($actionCell)
.append($multiplicityCell);
$tr
.append($labelCell)
.append($inputCell)
.append($actionCell)
.append($multiplicityCell);
if (valueAttr.type === 'label') {
if (definition.labelType === 'text') {
$input.prop("type", "text");
if (valueAttr.type === 'label') {
if (definition.labelType === 'text') {
$input.prop("type", "text");
// no need to await for this, can be done asynchronously
server.get('attributes/values/' + encodeURIComponent(valueAttr.name)).then(attributeValues => {
if (attributeValues.length === 0) {
return;
}
// no need to await for this, can be done asynchronously
server.get('attributes/values/' + encodeURIComponent(valueAttr.name)).then(attributeValues => {
if (attributeValues.length === 0) {
return;
attributeValues = attributeValues.map(attribute => { return { value: attribute }; });
$input.autocomplete({
appendTo: document.querySelector('body'),
hint: false,
autoselect: false,
openOnFocus: true,
minLength: 0,
tabAutocomplete: false
}, [{
displayKey: 'value',
source: function (term, cb) {
term = term.toLowerCase();
const filtered = attributeValues.filter(attr => attr.value.toLowerCase().includes(term));
cb(filtered);
}
}]);
});
}
else if (definition.labelType === 'number') {
$input.prop("type", "number");
let step = 1;
for (let i = 0; i < (definition.numberPrecision || 0) && i < 10; i++) {
step /= 10;
}
attributeValues = attributeValues.map(attribute => { return { value: attribute }; });
$input.prop("step", step);
}
else if (definition.labelType === 'boolean') {
$input.prop("type", "checkbox");
$input.autocomplete({
appendTo: document.querySelector('body'),
hint: false,
autoselect: false,
openOnFocus: true,
minLength: 0,
tabAutocomplete: false
}, [{
displayKey: 'value',
source: function (term, cb) {
term = term.toLowerCase();
if (valueAttr.value === "true") {
$input.prop("checked", "checked");
}
}
else if (definition.labelType === 'date') {
$input.prop("type", "date");
}
else if (definition.labelType === 'url') {
$input.prop("placeholder", "http://website...");
const filtered = attributeValues.filter(attr => attr.value.toLowerCase().includes(term));
const $openButton = $("<span>")
.addClass("input-group-text open-external-link-button jam jam-arrow-up-right")
.prop("title", "Open external link")
.click(() => window.open($input.val(), '_blank'));
cb(filtered);
}
}]);
$input.after($("<div>")
.addClass("input-group-append")
.append($openButton));
}
else {
messagingService.logError("Unknown labelType=" + definitionAttr.labelType);
}
}
else if (valueAttr.type === 'relation') {
if (valueAttr.value) {
$input.val(await treeUtils.getNoteTitle(valueAttr.value));
}
// no need to wait for this
noteAutocompleteService.initNoteAutocomplete($input);
$input.on('autocomplete:selected', (event, suggestion, dataset) => {
this.promotedAttributeChanged(event);
});
}
else if (definition.labelType === 'number') {
$input.prop("type", "number");
let step = 1;
for (let i = 0; i < (definition.numberPrecision || 0) && i < 10; i++) {
step /= 10;
}
$input.prop("step", step);
}
else if (definition.labelType === 'boolean') {
$input.prop("type", "checkbox");
if (valueAttr.value === "true") {
$input.prop("checked", "checked");
}
}
else if (definition.labelType === 'date') {
$input.prop("type", "date");
}
else if (definition.labelType === 'url') {
$input.prop("placeholder", "http://website...");
const $openButton = $("<span>")
.addClass("input-group-text open-external-link-button jam jam-arrow-up-right")
.prop("title", "Open external link")
.click(() => window.open($input.val(), '_blank'));
$input.after($("<div>")
.addClass("input-group-append")
.append($openButton));
$input.setSelectedPath(valueAttr.value);
}
else {
messagingService.logError("Unknown labelType=" + definitionAttr.labelType);
}
}
else if (valueAttr.type === 'relation') {
if (valueAttr.value) {
$input.val(await treeUtils.getNoteTitle(valueAttr.value));
messagingService.logError("Unknown attribute type=" + valueAttr.type);
return;
}
// no need to wait for this
noteAutocompleteService.initNoteAutocomplete($input);
if (definition.multiplicityType === "multivalue") {
const addButton = $("<span>")
.addClass("jam jam-plus pointer")
.prop("title", "Add new attribute")
.click(async () => {
const $new = await this.createPromotedAttributeRow(definitionAttr, {
attributeId: "",
type: valueAttr.type,
name: definitionAttr.name,
value: ""
});
$input.on('autocomplete:selected', function(event, suggestion, dataset) {
promotedAttributeChanged(event);
});
$tr.after($new);
$input.setSelectedPath(valueAttr.value);
}
else {
messagingService.logError("Unknown attribute type=" + valueAttr.type);
return;
}
if (definition.multiplicityType === "multivalue") {
const addButton = $("<span>")
.addClass("jam jam-plus pointer")
.prop("title", "Add new attribute")
.click(async () => {
const $new = await createPromotedAttributeRow(definitionAttr, {
attributeId: "",
type: valueAttr.type,
name: definitionAttr.name,
value: ""
$new.find('input').focus();
});
$tr.after($new);
const removeButton = $("<span>")
.addClass("jam jam-trash-alt pointer")
.prop("title", "Remove this attribute")
.click(async () => {
if (valueAttr.attributeId) {
await server.remove("notes/" + noteId + "/attributes/" + valueAttr.attributeId);
}
$new.find('input').focus();
});
$tr.remove();
});
const removeButton = $("<span>")
.addClass("jam jam-trash-alt pointer")
.prop("title", "Remove this attribute")
.click(async () => {
if (valueAttr.attributeId) {
await server.remove("notes/" + noteId + "/attributes/" + valueAttr.attributeId);
}
$multiplicityCell.append(addButton).append(" &nbsp;").append(removeButton);
}
$tr.remove();
});
$multiplicityCell.append(addButton).append(" &nbsp;").append(removeButton);
return $tr;
}
return $tr;
}
async promotedAttributeChanged(event) {
const $attr = $(event.target);
async function promotedAttributeChanged(event) {
const $attr = $(event.target);
let value;
let value;
if ($attr.prop("type") === "checkbox") {
value = $attr.is(':checked') ? "true" : "false";
}
else if ($attr.prop("attribute-type") === "relation") {
const selectedPath = $attr.getSelectedPath();
if ($attr.prop("type") === "checkbox") {
value = $attr.is(':checked') ? "true" : "false";
}
else if ($attr.prop("attribute-type") === "relation") {
const selectedPath = $attr.getSelectedPath();
value = selectedPath ? treeUtils.getNoteIdFromNotePath(selectedPath) : "";
}
else {
value = $attr.val();
}
value = selectedPath ? treeUtils.getNoteIdFromNotePath(selectedPath) : "";
}
else {
value = $attr.val();
}
const result = await server.put(`notes/${this.ctx.note.noteId}/attribute`, {
attributeId: $attr.prop("attribute-id"),
type: $attr.prop("attribute-type"),
name: $attr.prop("attribute-name"),
value: value
});
const result = await server.put("notes/" + noteDetailService.getActiveNoteId() + "/attribute", {
attributeId: $attr.prop("attribute-id"),
type: $attr.prop("attribute-type"),
name: $attr.prop("attribute-name"),
value: value
});
$attr.prop("attribute-id", result.attributeId);
$attr.prop("attribute-id", result.attributeId);
// animate only if it's not being animated already, this is important especially for e.g. number inputs
// which can be changed many times in a second by clicking on higher/lower buttons.
if ($savedIndicator.queue().length === 0) {
$savedIndicator.fadeOut();
$savedIndicator.fadeIn();
// animate only if it's not being animated already, this is important especially for e.g. number inputs
// which can be changed many times in a second by clicking on higher/lower buttons.
if (this.$savedIndicator.queue().length === 0) {
this.$savedIndicator.fadeOut();
this.$savedIndicator.fadeIn();
}
}
}
export default {
getAttributes,
showAttributes,
refreshAttributes,
invalidateAttributes
}
export default Attributes;

View File

@ -2,9 +2,11 @@ import treeService from "./tree.js";
import protectedSessionHolder from "./protected_session_holder.js";
import server from "./server.js";
import bundleService from "./bundle.js";
import attributeService from "./attributes.js";
import Attributes from "./attributes.js";
import treeUtils from "./tree_utils.js";
import utils from "./utils.js";
import {NoteTypeContext} from "./note_type.js";
import noteDetailService from "./note_detail.js";
import noteDetailCode from "./note_detail_code.js";
import noteDetailText from "./note_detail_text.js";
import noteDetailFile from "./note_detail_file.js";
@ -44,6 +46,8 @@ class NoteContext {
this.$savedIndicator = this.$noteTabContent.find(".saved-indicator");
this.noteChangeDisabled = false;
this.isNoteChanged = false;
this.attributes = new Attributes(this);
this.noteType = new NoteTypeContext(this);
this.components = {};
this.$noteTitle.on('input', () => {
@ -70,6 +74,8 @@ class NoteContext {
this.$noteTabContent.attr('data-note-id', note.noteId);
chromeTabs.updateTab(this.tab, {title: note.title});
this.attributes.invalidateAttributes();
}
getComponent(type) {
@ -90,7 +96,7 @@ class NoteContext {
}
this.note.title = this.$noteTitle.val();
this.note.content = getActiveNoteContent(this.note);
this.note.content = noteDetailService.getActiveNoteContent();
// it's important to set the flag back to false immediatelly after retrieving title and content
// otherwise we might overwrite another change (especially async code)
@ -127,9 +133,7 @@ class NoteContext {
}
async showChildrenOverview() {
return; // FIXME
const attributes = await attributeService.getAttributes();
const attributes = await this.attributes.getAttributes();
const hideChildrenOverview = attributes.some(attr => attr.type === 'label' && attr.name === 'hideChildrenOverview')
|| this.note.type === 'relation-map'
|| this.note.type === 'image'

View File

@ -9,7 +9,6 @@ import infoService from "./info.js";
import treeCache from "./tree_cache.js";
import NoteFull from "../entities/note_full.js";
import bundleService from "./bundle.js";
import attributeService from "./attributes.js";
import utils from "./utils.js";
import importDialog from "../dialogs/import.js";
@ -167,8 +166,8 @@ async function loadNoteDetail(noteId, newTab = false) {
ctx.$noteTitle.val(ctx.note.title);
if (utils.isDesktop()) {
noteTypeService.setNoteType(ctx.note.type);
noteTypeService.setNoteMime(ctx.note.mime);
ctx.noteType.type(ctx.note.type);
ctx.noteType.mime(ctx.note.mime);
}
for (const componentType in ctx.components) {
@ -204,11 +203,11 @@ async function loadNoteDetail(noteId, newTab = false) {
await bundleService.executeRelationBundles(ctx.note, 'runOnNoteView');
// if (utils.isDesktop()) {
// await attributeService.showAttributes();
//
// await ctx.showChildrenOverview();
// }
if (utils.isDesktop()) {
await ctx.attributes.showAttributes();
await ctx.showChildrenOverview();
}
}
async function loadNote(noteId) {
@ -293,5 +292,6 @@ export default {
focusAndSelectTitle,
saveNotesIfChanged,
onNoteChange,
addDetailLoadedListener
addDetailLoadedListener,
getActiveContext
};

View File

@ -8,6 +8,7 @@ class NoteDetailImage {
* @param {NoteContext} ctx
*/
constructor(ctx) {
this.ctx = ctx;
this.$component = ctx.$noteTabContent.find('.note-detail-image');
this.$imageWrapper = ctx.$noteTabContent.find('.note-detail-image-wrapper');
this.$imageView = ctx.$noteTabContent.find('.note-detail-image-view');
@ -42,18 +43,16 @@ class NoteDetailImage {
}
async show() {
const activeNote = noteDetailService.getActiveNote();
const attributes = await server.get('notes/' + activeNote.noteId + '/attributes');
const attributes = await server.get('notes/' + this.ctx.note.noteId + '/attributes');
const attributeMap = utils.toObject(attributes, l => [l.name, l.value]);
this.$component.show();
this.$fileName.text(attributeMap.originalFileName || "?");
this.$fileSize.text((attributeMap.fileSize || "?") + " bytes");
this.$fileType.text(activeNote.mime);
this.$fileType.text(this.ctx.note.mime);
this.$imageView.prop("src", `api/images/${activeNote.noteId}/${activeNote.title}`);
this.$imageView.prop("src", `api/images/${this.ctx.note.noteId}/${this.ctx.note.title}`);
}
selectImage(element) {

View File

@ -1,7 +1,5 @@
import libraryLoader from "./library_loader.js";
import noteDetailService from './note_detail.js';
import treeService from './tree.js';
import attributeService from "./attributes.js";
class NoteDetailText {
/**
@ -69,7 +67,7 @@ class NoteDetailText {
}
async isReadOnly() {
const attributes = await attributeService.getAttributes();
const attributes = await this.ctx.attributes.getAttributes();
return attributes.some(attr => attr.type === 'label' && attr.name === 'readOnly');
}

View File

@ -4,10 +4,6 @@ import server from './server.js';
import infoService from "./info.js";
import confirmDialog from "../dialogs/confirm.js";
const $executeScriptButton = $("#execute-script-button");
const $toggleEditButton = $('#toggle-edit-button');
const $renderButton = $('#render-button');
const DEFAULT_MIME_TYPES = [
{ mime: 'text/x-csrc', title: 'C' },
{ mime: 'text/x-c++src', title: 'C++' },
@ -45,15 +41,24 @@ const DEFAULT_MIME_TYPES = [
{ mime: 'text/x-yaml', title: 'YAML' }
];
let noteTypeModel;
let mimeTypes = DEFAULT_MIME_TYPES;
function NoteTypeModel() {
/**
* @param {NoteContext} ctx
* @constructor
*/
function NoteTypeContext(ctx) {
const self = this;
this.$executeScriptButton = ctx.$noteTabContent.find(".execute-script-button");
this.$toggleEditButton = ctx.$noteTabContent.find('.toggle-edit-button');
this.$renderButton = ctx.$noteTabContent.find('.render-button');
this.ctx = ctx;
this.type = ko.observable('text');
this.mime = ko.observable('');
this.codeMimeTypes = ko.observableArray(DEFAULT_MIME_TYPES);
this.codeMimeTypes = ko.observableArray(mimeTypes);
this.typeString = function() {
const type = self.type();
@ -97,9 +102,7 @@ function NoteTypeModel() {
};
async function save() {
const note = noteDetailService.getActiveNote();
await server.put('notes/' + note.noteId
await server.put('notes/' + self.ctx.note.noteId
+ '/type/' + encodeURIComponent(self.type())
+ '/mime/' + encodeURIComponent(self.mime()));
@ -175,32 +178,21 @@ function NoteTypeModel() {
};
this.updateExecuteScriptButtonVisibility = function() {
$executeScriptButton.toggle(self.mime().startsWith('application/javascript'));
self.$executeScriptButton.toggle(self.mime().startsWith('application/javascript'));
$toggleEditButton.toggle(self.type() === 'render');
$renderButton.toggle(self.type() === 'render');
}
}
self.$toggleEditButton.toggle(self.type() === 'render');
self.$renderButton.toggle(self.type() === 'render');
};
function init() {
noteTypeModel = new NoteTypeModel();
ko.applyBindings(noteTypeModel, document.getElementById('note-type-wrapper'));
ko.applyBindings(this, ctx.$noteTabContent.find('.note-type-wrapper')[0])
}
export default {
getNoteType: () => noteTypeModel.type(),
setNoteType: type => noteTypeModel.type(type),
getNoteMime: () => noteTypeModel.mime(),
setNoteMime: mime => {
noteTypeModel.mime(mime);
noteTypeModel.updateExecuteScriptButtonVisibility();
},
getDefaultCodeMimeTypes: () => DEFAULT_MIME_TYPES.slice(),
getCodeMimeTypes: () => noteTypeModel.codeMimeTypes(),
setCodeMimeTypes: types => noteTypeModel.codeMimeTypes(types),
init
getCodeMimeTypes: () => mimeTypes,
setCodeMimeTypes: types => { mimeTypes = types; }
};
export {
NoteTypeContext
};

View File

@ -412,7 +412,7 @@ div.ui-tooltip {
font-size: larger;
}
#children-overview {
.children-overview {
flex-grow: 1000;
flex-shrink: 1000;
flex-basis: 0;