trilium/src/public/javascripts/dialogs/attributes.js

145 lines
4 KiB
JavaScript
Raw Normal View History

"use strict";
const attributesDialog = (function() {
const dialogEl = $("#attributes-dialog");
2018-01-12 10:40:09 +08:00
const attributesModel = new AttributesModel();
let attributeNames = [];
2018-01-12 10:40:09 +08:00
function AttributesModel() {
const self = this;
2018-01-12 10:40:09 +08:00
this.attributes = ko.observableArray();
this.loadAttributes = async function() {
const noteId = noteEditor.getCurrentNoteId();
const attributes = await server.get('notes/' + noteId + '/attributes');
2018-02-05 06:22:21 +08:00
self.attributes(attributes.map(ko.observable));
2018-02-05 06:22:21 +08:00
addLastEmptyRow();
attributeNames = await server.get('attributes/names');
$(".attribute-name:last").focus();
2018-01-12 10:40:09 +08:00
};
2018-02-05 06:22:21 +08:00
function isValid() {
for (let attrs = self.attributes(), i = 0; i < attrs.length; i++) {
if (self.isEmptyName(i) || self.isNotUnique(i)) {
return false;
}
}
return true;
}
2018-01-12 10:40:09 +08:00
this.save = async function() {
2018-02-05 06:22:21 +08:00
if (!isValid()) {
alert("Please fix all validation errors and try saving again.");
return;
}
2018-01-12 10:40:09 +08:00
const noteId = noteEditor.getCurrentNoteId();
2018-02-05 06:22:21 +08:00
const attributesToSave = self.attributes()
.map(attr => attr())
.filter(attr => attr.attributeId !== "" || attr.name !== "");
const attributes = await server.put('notes/' + noteId + '/attributes', attributesToSave);
self.attributes(attributes.map(ko.observable));
2018-01-12 10:40:09 +08:00
2018-02-05 06:22:21 +08:00
addLastEmptyRow();
2018-01-12 10:40:09 +08:00
showMessage("Attributes have been saved.");
};
2018-02-05 06:22:21 +08:00
function addLastEmptyRow() {
const attrs = self.attributes();
const last = attrs[attrs.length - 1]();
if (last.name.trim() !== "" || last.value !== "") {
self.attributes.push(ko.observable({
attributeId: '',
name: '',
value: ''
}));
}
}
this.attributeChanged = function (row) {
addLastEmptyRow();
for (const attr of self.attributes()) {
if (row.attributeId === attr().attributeId) {
attr.valueHasMutated();
}
}
};
this.isNotUnique = function(index) {
const cur = self.attributes()[index]();
if (cur.name.trim() === "") {
return false;
}
for (let attrs = self.attributes(), i = 0; i < attrs.length; i++) {
const attr = attrs[i]();
if (index !== i && cur.name === attr.name) {
return true;
}
}
return false;
};
this.isEmptyName = function(index) {
const cur = self.attributes()[index]();
return cur.name.trim() === "" && (cur.attributeId !== "" || cur.value !== "");
}
}
async function showDialog() {
glob.activeDialog = dialogEl;
dialogEl.dialog({
modal: true,
width: 800,
2018-02-04 01:44:22 +08:00
height: 500
});
2018-01-12 10:40:09 +08:00
attributesModel.loadAttributes();
}
$(document).bind('keydown', 'alt+a', e => {
showDialog();
e.preventDefault();
});
2018-01-22 12:06:25 +08:00
ko.applyBindings(attributesModel, document.getElementById('attributes-dialog'));
2018-01-12 10:40:09 +08:00
$(document).on('focus', '.attribute-name:not(.ui-autocomplete-input)', function (e) {
$(this).autocomplete({
// shouldn't be required and autocomplete should just accept array of strings, but that fails
// because we have overriden filter() function in init.js
source: attributeNames.map(attr => {
return {
label: attr,
value: attr
}
}),
minLength: 0
});
$(this).autocomplete("search", $(this).val());
});
return {
showDialog
};
})();