Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions new-note-namer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# New note namer

Sets the note title and file name at creation time, with optional dialogs for each field.
Especially useful when the _Allow note file name to be different from note title_ option is enabled in QOwnNotes.

## Settings

| Setting | Description |
| ------------------------------------------ | ----------------------------------------------------------------------------------- |
| **Show a dialog to define the note title** | If checked, a dialog asks for a custom title (pre-filled with the search term). |
| **Show a dialog to define the file name** | If checked, a dialog asks for a custom file name (pre-filled with the search term). |
| **Heading style** | Format applied to the title: ATX (`# Title`), Setext (`Title / =====`), or Custom. |
| **Custom heading – opening tag** | Text inserted before the title (Custom style only). |
| **Custom heading – closing tag** | Text inserted after the title (Custom style only). |

The two dialog options are independent: each defaults to the search term, regardless of the other.

## Behaviour

| Source | Dialog: note title | Dialog: file name | Title | File name |
| ---------------- | ------------------ | ----------------- | ---------------------------- | ------------------------------------------- |
| Search "foo" | ☐ | ☐ | `# foo` | `foo` |
| Search "foo" | ☑ | ☐ | dialog pre-filled with `foo` | `foo` (search term, independent from title) |
| Search "foo" | ☐ | ☑ | `# foo` | dialog pre-filled with `foo` |
| Search "foo" | ☑ | ☑ | dialog pre-filled with `foo` | dialog pre-filled with `foo` |
| Menu (no search) | — | ☐ | dialog (no pre-fill) | = entered title |
| Menu (no search) | — | ☑ | dialog (no pre-fill) | dialog pre-filled with entered title |

> **Note:** the `n:` search prefix (name-only filter) is automatically stripped from the note name.

## Tips

- Leave both dialogs unchecked for a fully automatic workflow: create a note directly from the search bar with one keypress.
- Check only _file name_ to keep the search term as the title but write a longer or different file name.
- Check only _title_ to write a custom heading while keeping the file name equal to the search term.
- The heading style applies in all cases, including when no dialog is shown.
- All settings require a **script engine reload** to take effect after being changed.
6 changes: 3 additions & 3 deletions new-note-namer/info.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
"name": "New note namer",
"identifier": "new-note-namer",
"script": "new-note-namer.qml",
"authors": ["@diegovskytl", "@Mystechry"],
"authors": ["@diegovskytl", "@Mystechry", "@luginf"],
"platforms": ["linux", "macos", "windows"],
"version": "0.0.2",
"version": "0.0.4",
"minAppVersion": "17.06.2",
"description": "Enables a dialog window (or two) so the user can choose the note title and file name at the moment of creation. <br> Specially useful when the 'Allow note file name to be different to note title. \n No more cumbersome renaming :)"
"description": "Enables a dialog window (or two, or even none) so the user can choose the note title and file name at the moment of creation, or simply use the search term for the filename and title of the note with custom formattings. <br><br> Specially useful when the 'Allow note file name to be different to note title. \n No more cumbersome renaming :)"
}
115 changes: 80 additions & 35 deletions new-note-namer/new-note-namer.qml
Original file line number Diff line number Diff line change
Expand Up @@ -7,63 +7,108 @@ import QOwnNotesTypes 1.0
Avoids cumbersome renaming and title editing.
*/
QtObject {
property bool extraDialogForTitle
property bool extraDialogForFileName
property string headingStyle
property string _searchTerm: ""
property string customHeadingOpen
property string customHeadingClose
property variant settingsVariables: [
{
'identifier': 'extraDialogForFileName',
'name': 'Extra dialog for note title',
'description': 'Show an additional dialog window so user can write a file name different to the note title.',
'identifier': 'extraDialogForTitle',
'name': 'Show a dialog to define the note title',
'description': 'If checked, ask for a custom note title.',
'type': 'boolean',
'default': 'false'
},
{
'identifier': 'underlineHeading',
'name': 'Underline heading',
'description': 'Highlight the first line by underlining it with =, if not checked, use a preceding # instead.',
'identifier': 'extraDialogForFileName',
'name': 'Show a dialog to define the file name',
'description': 'If checked, ask for a custom file name.',
'type': 'boolean',
'default': 'false'
},
{
'identifier': 'headingStyle',
'name': 'Heading style',
'description': 'Title format for new notes.',
'type': 'selection',
'default': '0',
'items': {
'0': 'ATX Markdown heading (# Title)',
'1': 'Setext Markdown heading (Title / =====)',
'2': 'Custom heading (opening and closing tags)'
}
},
{
'identifier': 'customHeadingOpen',
'name': 'Custom heading – opening tag',
'description': 'Text inserted before the note name (only used when heading style is "Custom").',
'type': 'string',
'default': ''
},
{
'identifier': 'customHeadingClose',
'name': 'Custom heading – closing tag',
'description': 'Text inserted after the note name (only used when heading style is "Custom").',
'type': 'string',
'default': ''
},
]
property bool underlineHeading

function handleNewNoteHeadlineHook(note) {
var newName = newNamer("New note", "New note title", "Title");
script.log(note.fileCreated);
script.log(note.fileLastModified);

if (underlineHeading) {
return newName + "\n" + "=".repeat(newName.length);
function handleNewNoteHeadlineHook(headline) {
// 'headline' is a plain string (the search term or default text), not a Note object.
// Strip QOwnNotes search filter prefixes (e.g. "n:" for name-only search).
_searchTerm = headline.replace(/^n:/i, "");
var name;
if (extraDialogForTitle || _searchTerm === "") {
// Show dialog: pre-fill with the search term if available, otherwise a placeholder.
name = newNamer("New note", "New note title", _searchTerm !== "" ? _searchTerm : "Title");
} else {
return "# " + newName;
// If already provided (search term or QOwnNotes own dialog), use it directly.
name = _searchTerm;
}
return buildHeadline(name);
}
function handleNoteTextFileNameHook(note) {
script.log("note name: " + note.name);
script.log("file name: " + note.fileName);
script.log(note.fileCreated);
script.log(note.fileLastModified);

var noteLines = note.noteText.split("\n");
var firstLine = noteLines[0];
var noteTitle = firstLine.slice(2); // Remove the preceding "# "
if (underlineHeading) {
// Underlined headings use the entire first line
noteTitle = firstLine;
function buildHeadline(name) {
if (headingStyle === "2") {
return customHeadingOpen + name + customHeadingClose;
}

script.log("note title: " + noteTitle);

// right when a note is created, the fileCreated property value is 'Invald Date'
// this blocks the hook to further change the note file name if the note title is changed
if (headingStyle === "1") {
return name + "\n" + "=".repeat(name.length);
}
return "# " + name; // "0" (ATX) or unset
}
function extractTitle(noteText) {
var firstLine = (noteText || "").split("\n")[0];
if (headingStyle === "2") {
var t = firstLine.slice(customHeadingOpen.length);
var closeLen = customHeadingClose.length;
if (closeLen > 0 && t.slice(-closeLen) === customHeadingClose) {
t = t.slice(0, t.length - closeLen);
}
return t;
}
if (headingStyle === "1") {
return firstLine; // setext: first line is the bare title
}
return firstLine.slice(2); // ATX: remove "# "
}
function handleNoteTextFileNameHook(note) {
// right when a note is created, the fileCreated property value is 'Invalid Date'
// this blocks the hook from further changing the note file name if the note title is changed
if (note.fileCreated != "Invalid Date") {
return "";
}

// Default file name: search term if available, otherwise derived from the title.
var defaultName = _searchTerm !== "" ? _searchTerm : extractTitle(note.noteText);

if (extraDialogForFileName) {
return newNamer("New note", "New file name", "File name");
} else {
return noteTitle;
return newNamer("New note", "New file name", defaultName);
}

return defaultName;
}
function init() {
script.log("New-note-namer active");
Expand Down
Loading