@@ -157,6 +157,7 @@ class OpenNotebook {
157157 await this . loadConfig ( ) ;
158158 this . bindEvents ( ) ;
159159 this . initResizers ( ) ;
160+ this . initNotebookNameEditor ( ) ;
160161 this . switchView ( 'landing' ) ;
161162
162163 // 清理过期缓存
@@ -171,7 +172,8 @@ class OpenNotebook {
171172 const config = await this . api ( '/config' ) ;
172173 // Convert snake_case to camelCase
173174 this . config = {
174- allowDelete : config . allow_delete !== undefined ? config . allow_delete : true
175+ allowDelete : config . allow_delete !== undefined ? config . allow_delete : true ,
176+ allowNotebookRename : config . allow_notebook_rename !== undefined ? config . allow_notebook_rename : true
175177 } ;
176178 } catch ( error ) {
177179 console . error ( 'Failed to load config:' , error ) ;
@@ -621,10 +623,19 @@ class OpenNotebook {
621623
622624 async selectNotebook ( id ) {
623625 this . currentNotebook = this . notebooks . find ( nb => nb . id === id ) ;
624-
625- document . getElementById ( 'currentNotebookName' ) . textContent = this . currentNotebook . name ;
626+
627+ const nameDisplay = document . getElementById ( 'currentNotebookName' ) ;
628+ nameDisplay . textContent = this . currentNotebook . name ;
629+
630+ // 设置可编辑状态
631+ if ( this . config . allowNotebookRename ) {
632+ nameDisplay . classList . add ( 'editable' ) ;
633+ } else {
634+ nameDisplay . classList . remove ( 'editable' ) ;
635+ }
636+
626637 this . switchView ( 'workspace' ) ;
627-
638+
628639 // Reset tab to notes list and remove any existing note view
629640 this . showNotesListTab ( ) ;
630641 const noteView = document . querySelector ( '.note-view-container' ) ;
@@ -639,6 +650,110 @@ class OpenNotebook {
639650 this . setStatus ( `当前选择: ${ this . currentNotebook . name } ` ) ;
640651 }
641652
653+ initNotebookNameEditor ( ) {
654+ const nameDisplay = document . getElementById ( 'currentNotebookName' ) ;
655+ const nameEditor = document . getElementById ( 'notebookNameEditor' ) ;
656+ const nameInput = document . getElementById ( 'notebookNameInput' ) ;
657+ const saveBtn = document . getElementById ( 'btnSaveNotebookName' ) ;
658+ const cancelBtn = document . getElementById ( 'btnCancelNotebookName' ) ;
659+
660+ // 双击进入编辑模式
661+ nameDisplay . addEventListener ( 'dblclick' , ( ) => {
662+ if ( ! this . config . allowNotebookRename ) return ;
663+ this . startEditingNotebookName ( ) ;
664+ } ) ;
665+
666+ // 点击保存按钮
667+ saveBtn . addEventListener ( 'click' , ( ) => {
668+ this . saveNotebookName ( ) ;
669+ } ) ;
670+
671+ // 点击取消按钮
672+ cancelBtn . addEventListener ( 'click' , ( ) => {
673+ this . cancelEditNotebookName ( ) ;
674+ } ) ;
675+
676+ // 输入框回车保存
677+ nameInput . addEventListener ( 'keydown' , ( e ) => {
678+ if ( e . key === 'Enter' ) {
679+ this . saveNotebookName ( ) ;
680+ } else if ( e . key === 'Escape' ) {
681+ this . cancelEditNotebookName ( ) ;
682+ }
683+ } ) ;
684+ }
685+
686+ startEditingNotebookName ( ) {
687+ const nameDisplay = document . getElementById ( 'currentNotebookName' ) ;
688+ const nameEditor = document . getElementById ( 'notebookNameEditor' ) ;
689+ const nameInput = document . getElementById ( 'notebookNameInput' ) ;
690+
691+ nameInput . value = this . currentNotebook . name ;
692+ nameDisplay . classList . add ( 'hidden' ) ;
693+ nameEditor . classList . remove ( 'hidden' ) ;
694+ nameInput . focus ( ) ;
695+ nameInput . select ( ) ;
696+ }
697+
698+ async saveNotebookName ( ) {
699+ const nameInput = document . getElementById ( 'notebookNameInput' ) ;
700+ const newName = nameInput . value . trim ( ) ;
701+
702+ if ( ! newName ) {
703+ this . showError ( '笔记本名称不能为空' ) ;
704+ return ;
705+ }
706+
707+ if ( newName === this . currentNotebook . name ) {
708+ this . cancelEditNotebookName ( ) ;
709+ return ;
710+ }
711+
712+ try {
713+ this . showLoading ( '保存中...' ) ;
714+
715+ const updated = await this . api ( `/notebooks/${ this . currentNotebook . id } ` , {
716+ method : 'PUT' ,
717+ body : JSON . stringify ( {
718+ name : newName ,
719+ description : this . currentNotebook . description
720+ } )
721+ } ) ;
722+
723+ // 更新本地数据
724+ this . currentNotebook . name = newName ;
725+ this . currentNotebook . updated_at = updated . updated_at ;
726+
727+ // 更新 notebooks 列表中的数据
728+ const nb = this . notebooks . find ( n => n . id === this . currentNotebook . id ) ;
729+ if ( nb ) {
730+ nb . name = newName ;
731+ nb . updated_at = updated . updated_at ;
732+ }
733+
734+ // 使缓存失效
735+ this . cache . delete ( 'notebooks' ) ;
736+
737+ // 更新显示
738+ document . getElementById ( 'currentNotebookName' ) . textContent = newName ;
739+ this . cancelEditNotebookName ( ) ;
740+ this . hideLoading ( ) ;
741+ this . setStatus ( '笔记本名称已更新' ) ;
742+
743+ } catch ( error ) {
744+ this . hideLoading ( ) ;
745+ this . showError ( error . message ) ;
746+ }
747+ }
748+
749+ cancelEditNotebookName ( ) {
750+ const nameDisplay = document . getElementById ( 'currentNotebookName' ) ;
751+ const nameEditor = document . getElementById ( 'notebookNameEditor' ) ;
752+
753+ nameDisplay . classList . remove ( 'hidden' ) ;
754+ nameEditor . classList . add ( 'hidden' ) ;
755+ }
756+
642757 showNewNotebookModal ( ) {
643758 document . getElementById ( 'newNotebookModal' ) . classList . add ( 'active' ) ;
644759 document . getElementById ( 'modalOverlay' ) . classList . add ( 'active' ) ;
0 commit comments