diff --git a/src/public/javascripts/services/note_detail.js b/src/public/javascripts/services/note_detail.js
index a0425e964..bc7503cb5 100644
--- a/src/public/javascripts/services/note_detail.js
+++ b/src/public/javascripts/services/note_detail.js
@@ -228,7 +228,7 @@ async function loadAttributes() {
const promoted = attributes.filter(attr => (attr.type === 'label-definition' || attr.type === 'relation-definition') && attr.value.isPromoted);
- let idx = 2; // because idx is also tabIndex and 1 is the title
+ let idx = 1;
async function createRow(definitionAttr, valueAttr) {
const definition = definitionAttr.value;
@@ -237,7 +237,7 @@ async function loadAttributes() {
const $labelCell = $("
").append(valueAttr.name);
const $input = $("")
.prop("id", inputId)
- .prop("tabindex", idx)
+ .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)
@@ -318,7 +318,8 @@ async function loadAttributes() {
$input.val((await treeUtils.getNoteTitle(valueAttr.value) + " (" + valueAttr.value + ")"));
}
- await noteAutocompleteService.initNoteAutocomplete($input);
+ // no need to wait for this
+ noteAutocompleteService.initNoteAutocomplete($input);
}
else {
messagingService.logError("Unknown attribute type=" + valueAttr.type);
@@ -338,6 +339,8 @@ async function loadAttributes() {
});
$tr.after($new);
+
+ $new.find('input').focus();
});
const removeButton = $("")
@@ -358,6 +361,8 @@ async function loadAttributes() {
}
if (promoted.length > 0) {
+ const $tbody = $("");
+
for (const definitionAttr of promoted) {
const definitionType = definitionAttr.type;
const valueType = definitionType.substr(0, definitionType.length - 11);
@@ -380,9 +385,13 @@ async function loadAttributes() {
for (const valueAttr of valueAttrs) {
const $tr = await createRow(definitionAttr, valueAttr);
- $promotedAttributesContainer.append($tr);
+ $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)
+ $promotedAttributesContainer.empty().append($tbody);
}
else {
$attributeListInner.html('');
diff --git a/src/public/javascripts/services/script_api.js b/src/public/javascripts/services/script_api.js
index b17b4be59..ec1262ae2 100644
--- a/src/public/javascripts/services/script_api.js
+++ b/src/public/javascripts/services/script_api.js
@@ -11,6 +11,12 @@ function ScriptApi(startNote, currentNote, originEntity = null) {
await treeService.activateNode(notePath);
}
+ async function activateNewNote(notePath) {
+ await treeService.reload();
+
+ await treeService.activateNode(notePath, true);
+ }
+
function addButtonToToolbar(buttonId, button) {
$("#" + buttonId).remove();
@@ -57,6 +63,7 @@ function ScriptApi(startNote, currentNote, originEntity = null) {
originEntity: originEntity,
addButtonToToolbar,
activateNote,
+ activateNewNote,
getInstanceName: () => window.glob.instanceName,
runOnServer,
formatDateISO: utils.formatDateISO,
diff --git a/src/public/javascripts/services/tree.js b/src/public/javascripts/services/tree.js
index 15c86ca58..831687cc3 100644
--- a/src/public/javascripts/services/tree.js
+++ b/src/public/javascripts/services/tree.js
@@ -100,11 +100,15 @@ async function expandToNote(notePath, expandOpts) {
}
}
-async function activateNode(notePath) {
+async function activateNode(notePath, newNote) {
utils.assertArguments(notePath);
const node = await expandToNote(notePath);
+ if (newNote) {
+ noteDetailService.newNoteCreated();
+ }
+
// we use noFocus because when we reload the tree because of background changes
// we don't want the reload event to steal focus from whatever was focused before
await node.setActive(true, { noFocus: true });
diff --git a/src/views/index.ejs b/src/views/index.ejs
index d39a25f97..121b82f3c 100644
--- a/src/views/index.ejs
+++ b/src/views/index.ejs
@@ -184,7 +184,7 @@
|