Keep files plugin note-neutral
This commit is contained in:
parent
39d8df339b
commit
fca7716e75
|
|
@ -145,35 +145,11 @@
|
|||
return dot > 0 ? name.slice(dot + 1).toLowerCase() : '';
|
||||
}
|
||||
|
||||
function normalizeNoteFilename(title) {
|
||||
var value = String(title == null ? '' : title).trim();
|
||||
if (/\.markdown$/i.test(value) && value.length > 9) value = value.slice(0, -9);
|
||||
else if (/\.md$/i.test(value) && value.length > 3) value = value.slice(0, -3);
|
||||
if (!value) throw new Error('note title must not be empty');
|
||||
value = value.replace(/\s+/g, '_');
|
||||
value = value.replace(/[\u2012\u2013\u2014\u2015\u2212]/g, '-');
|
||||
value = value.replace(/[<>:"/\\|?*\x00-\x1f\x7f]/g, '');
|
||||
var out = '';
|
||||
for (var i = 0; i < value.length; i++) {
|
||||
var ch = value.charAt(i);
|
||||
if (/[A-Za-z0-9._-]/.test(ch) || /[\p{L}\p{N}]/u.test(ch)) out += ch;
|
||||
else if (/\S/.test(ch)) out += '_';
|
||||
}
|
||||
out = out.replace(/[_.-]+/g, '_').replace(/^[._\-\s]+|[._\-\s]+$/g, '');
|
||||
if (!out) throw new Error('note title normalizes to an empty filename');
|
||||
return out + '.md';
|
||||
}
|
||||
|
||||
function isConflictError(err) {
|
||||
var msg = (err && err.message) ? err.message : String(err || '');
|
||||
return /conflict|already exists|exists/i.test(msg);
|
||||
}
|
||||
|
||||
function isNotFoundError(err) {
|
||||
var msg = (err && err.message) ? err.message : String(err || '');
|
||||
return /not.?found|does not exist|no such/i.test(msg);
|
||||
}
|
||||
|
||||
var FILE_ICONS = {
|
||||
folder: 'M3 5a2 2 0 0 1 2-2h5l2 3h7a2 2 0 0 1 2 2v1H3V5Zm0 6h18v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-7Z',
|
||||
markdown: 'M5 3h10l4 4v14H5V3Zm9 1.5V8h3.5L14 4.5ZM8 11h8v2H8v-2Zm0 4h8v2H8v-2Z',
|
||||
|
|
@ -314,56 +290,6 @@
|
|||
return full.indexOf(workspaceRoot + '/') === 0 ? full.slice(workspaceRoot.length + 1) : full;
|
||||
}
|
||||
|
||||
function ensureFolder(path) {
|
||||
return api.files.createFolder(path).catch(function (err) {
|
||||
if (!isConflictError(err)) throw err;
|
||||
});
|
||||
}
|
||||
|
||||
function createNoteInFolder(notesFolderPath, title) {
|
||||
var trimmedTitle = String(title || '').trim();
|
||||
if (!trimmedTitle) return Promise.reject(new Error('note title must not be empty'));
|
||||
var notePath = cleanPath(notesFolderPath) + '/' + normalizeNoteFilename(trimmedTitle);
|
||||
return ensureFolder(notesFolderPath).then(function () {
|
||||
return api.files.metadata(notePath).then(function () {
|
||||
return { path: notePath, conflict: true };
|
||||
}).catch(function (err) {
|
||||
if (!isNotFoundError(err)) throw err;
|
||||
return api.files.writeText(notePath, '# ' + trimmedTitle + '\n', {
|
||||
createIfMissing: true,
|
||||
overwrite: false
|
||||
}).then(function () {
|
||||
return { path: notePath };
|
||||
}).catch(function (writeErr) {
|
||||
if (isConflictError(writeErr)) return { path: notePath, conflict: true };
|
||||
throw writeErr;
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function ensureOverviewInFolder(notesFolderPath) {
|
||||
var folderPath = cleanPath(notesFolderPath);
|
||||
var ovPath = folderPath + '/Overview.md';
|
||||
return api.files.metadata(ovPath).then(function () {
|
||||
return { path: ovPath };
|
||||
}).catch(function (err) {
|
||||
if (!isNotFoundError(err)) throw err;
|
||||
return ensureFolder(folderPath).then(function () {
|
||||
var local = localPath(folderPath);
|
||||
var parentName = baseName(parentPath(local)) || baseName(folderPath) || 'Overview';
|
||||
return api.files.writeText(ovPath, '# ' + parentName + '\n', {
|
||||
createIfMissing: true,
|
||||
overwrite: false
|
||||
}).catch(function (writeErr) {
|
||||
if (!isConflictError(writeErr)) throw writeErr;
|
||||
}).then(function () {
|
||||
return { path: ovPath };
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
var toolbar = el('div', { className: 'files-toolbar' });
|
||||
var breadcrumb = el('div', { className: 'files-breadcrumb' });
|
||||
var backBtn = iconButton('back', 'Back', 'back', goBack);
|
||||
|
|
@ -842,48 +768,6 @@
|
|||
}
|
||||
var isFolder = entry.type === 'folder';
|
||||
ctxMenu.appendChild(ctxItem(isFolder ? 'Open Folder' : 'Open', '', function () { openEntry(entry); }, 'open', 'open'));
|
||||
var entryLocalPath = localPath(entry.relativePath);
|
||||
var isNotes = entryLocalPath === 'Notes' || entryLocalPath.split('/')[0] === 'Notes';
|
||||
if (isNotes) {
|
||||
ctxMenu.appendChild(ctxSep());
|
||||
if (isFolder) {
|
||||
ctxMenu.appendChild(ctxItem('Create Note', '', function () {
|
||||
var title = prompt('Note title:');
|
||||
if (!title) return;
|
||||
createNoteInFolder(entry.relativePath, title).then(function (created) {
|
||||
if (created && created.conflict) {
|
||||
window.alert('A note with this title already exists.');
|
||||
return;
|
||||
}
|
||||
loadEntries();
|
||||
var notePath = (created && created.path) ? created.path : '';
|
||||
if (notePath) {
|
||||
api.workbench.openResource({
|
||||
kind: 'vault-file',
|
||||
path: notePath,
|
||||
mode: 'edit',
|
||||
extension: '.md',
|
||||
context: { notesMode: true, sourcePluginId: 'verstak.files' }
|
||||
}).catch(function () {});
|
||||
}
|
||||
}).catch(function (err) { window.alert('Failed to create note: ' + (err.message || String(err))); });
|
||||
}, 'create-note', 'markdownAdd'));
|
||||
ctxMenu.appendChild(ctxItem('Open Overview', '', function () {
|
||||
ensureOverviewInFolder(entry.relativePath).then(function (result) {
|
||||
var overviewPath = (result && result.path) ? result.path : '';
|
||||
if (overviewPath) {
|
||||
api.workbench.openResource({
|
||||
kind: 'vault-file',
|
||||
path: overviewPath,
|
||||
mode: 'view',
|
||||
extension: '.md',
|
||||
context: { notesMode: true, sourcePluginId: 'verstak.files' }
|
||||
}).catch(function () {});
|
||||
}
|
||||
}).catch(function (err) { window.alert('Failed to open overview: ' + (err.message || String(err))); });
|
||||
}, 'open-overview', 'open'));
|
||||
}
|
||||
}
|
||||
ctxMenu.appendChild(ctxSep());
|
||||
ctxMenu.appendChild(ctxItem('Rename', '', function () { beginRename(entry); }, 'rename', 'rename'));
|
||||
if (entry.type !== 'folder') {
|
||||
|
|
|
|||
|
|
@ -113,6 +113,36 @@ else
|
|||
echo " ⚠️ python3 not available — skipping frontend API boundary"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
# Keep Files plugin as a raw file explorer; note workflows belong to Notes.
|
||||
echo "[files plugin note boundaries]"
|
||||
if [ "$HAS_PYTHON" -eq 1 ]; then
|
||||
set +e
|
||||
python3 -c "
|
||||
import os, re, sys
|
||||
|
||||
path = '$ROOT/plugins/files/frontend/src/index.js'
|
||||
forbidden = re.compile(r'createNoteInFolder|ensureOverviewInFolder|Create Note|Open Overview')
|
||||
problems = []
|
||||
|
||||
with open(path, encoding='utf-8') as f:
|
||||
for lineno, line in enumerate(f, 1):
|
||||
if forbidden.search(line):
|
||||
problems.append(f'{os.path.relpath(path, \"$ROOT\")}:{lineno}: {line.strip()}')
|
||||
|
||||
if problems:
|
||||
for p in problems:
|
||||
print(' FAIL ' + p)
|
||||
sys.exit(1)
|
||||
print(' OK files plugin has no note creation or overview actions')
|
||||
"
|
||||
STATUS=$?
|
||||
set -e
|
||||
report "files plugin note boundaries" "$STATUS"
|
||||
else
|
||||
echo " ⚠️ python3 not available — skipping files plugin note boundaries"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
# Ensure source manifests do not require ignored dist files for plain JS plugins.
|
||||
echo "[frontend entry source contract]"
|
||||
|
|
|
|||
Loading…
Reference in New Issue