diff --git a/controllers/BookController.go b/controllers/BookController.go index f13faf79..7975f8c8 100644 --- a/controllers/BookController.go +++ b/controllers/BookController.go @@ -144,6 +144,7 @@ func (c *BookController) SaveBook() { isDownload := strings.TrimSpace(c.GetString("is_download")) == "on" enableShare := strings.TrimSpace(c.GetString("enable_share")) == "on" isUseFirstDocument := strings.TrimSpace(c.GetString("is_use_first_document")) == "on" + autoSave := strings.TrimSpace(c.GetString("auto_save")) == "on" if strings.Count(description, "") > 500 { c.JsonResult(6004, "项目描述不能大于500字") @@ -170,6 +171,7 @@ func (c *BookController) SaveBook() { book.HistoryCount = historyCount book.IsDownload = 0 + if autoRelease { book.AutoRelease = 1 } else { @@ -190,6 +192,11 @@ func (c *BookController) SaveBook() { } else { book.IsUseFirstDocument = 0 } + if autoSave { + book.AutoSave = 1 + }else{ + book.AutoSave = 0 + } if err := book.Update(); err != nil { c.JsonResult(6006, "保存失败") } diff --git a/models/BookModel.go b/models/BookModel.go index 1ca0faf8..73c4b03d 100644 --- a/models/BookModel.go +++ b/models/BookModel.go @@ -70,6 +70,8 @@ type Book struct { Version int64 `orm:"type(bigint);column(version)" json:"version"` //是否使用第一篇文章项目为默认首页,0 否/1 是 IsUseFirstDocument int `orm:"column(is_use_first_document);type(int);default(0)" json:"is_use_first_document"` + //是否开启自动保存:0 否/1 是 + AutoSave int `orm:"column(auto_save);type(tinyint);default(0)" json:"auto_save"` } func (book *Book) String() string { diff --git a/models/BookResult.go b/models/BookResult.go index eb78c27f..cec68830 100644 --- a/models/BookResult.go +++ b/models/BookResult.go @@ -26,8 +26,8 @@ import ( "encoding/json" ) -var( - exportLimitWorkerChannel = gopool.NewChannelPool(conf.GetExportLimitNum(),conf.GetExportQueueLimitNum()) +var ( + exportLimitWorkerChannel = gopool.NewChannelPool(conf.GetExportLimitNum(), conf.GetExportQueueLimitNum()) ) type BookResult struct { @@ -64,6 +64,7 @@ type BookResult struct { LastModifyText string `json:"last_modify_text"` IsDisplayComment bool `json:"is_display_comment"` IsDownload bool `json:"is_download"` + AutoSave bool `json:"auto_save"` } func NewBookResult() *BookResult { @@ -80,7 +81,7 @@ func (b *BookResult) String() string { } // 根据项目标识查询项目以及指定用户权限的信息. -func (m *BookResult) FindByIdentify(identify string, memberId int,cols ...string) (*BookResult, error) { +func (m *BookResult) FindByIdentify(identify string, memberId int, cols ...string) (*BookResult, error) { if identify == "" || memberId <= 0 { return m, ErrInvalidParameter } @@ -88,7 +89,7 @@ func (m *BookResult) FindByIdentify(identify string, memberId int,cols ...string book := NewBook() - err := o.QueryTable(book.TableNameWithPrefix()).Filter("identify", identify).One(book,cols...) + err := o.QueryTable(book.TableNameWithPrefix()).Filter("identify", identify).One(book, cols...) if err != nil { return m, err @@ -106,7 +107,7 @@ func (m *BookResult) FindByIdentify(identify string, memberId int,cols ...string err = o.QueryTable(relationship.TableNameWithPrefix()).Filter("book_id", book.BookId).Filter("role_id", 0).One(&relationship2) if err != nil { - logs.Error("根据项目标识查询项目以及指定用户权限的信息 => ", err) + logs.Error("根据项目标识查询项目以及指定用户权限的信息 -> ", err) return m, ErrPermissionDenied } @@ -199,6 +200,7 @@ func (m *BookResult) ToBookResult(book Book) *BookResult { m.Publisher = book.Publisher m.HistoryCount = book.HistoryCount m.IsDownload = book.IsDownload == 0 + m.AutoSave = book.AutoSave == 1 if book.Theme == "" { m.Theme = "default" @@ -224,10 +226,10 @@ func (m *BookResult) ToBookResult(book Book) *BookResult { } //后台转换 -func BackgroupConvert(sessionId string,bookResult *BookResult) error { +func BackgroupConvert(sessionId string, bookResult *BookResult) error { if err := converter.CheckConvertCommand(); err != nil { - beego.Error("检查转换程序失败 -> ",err) + beego.Error("检查转换程序失败 -> ", err) return err } err := exportLimitWorkerChannel.LoadOrStore(bookResult.Identify, func() { @@ -236,7 +238,7 @@ func BackgroupConvert(sessionId string,bookResult *BookResult) error { if err != nil { - beego.Error("将导出任务加入任务队列失败 -> ",err) + beego.Error("将导出任务加入任务队列失败 -> ", err) return err } exportLimitWorkerChannel.Start() @@ -257,27 +259,25 @@ func (m *BookResult) Converter(sessionId string) (ConvertBookResult, error) { docxpath := filepath.Join(outputPath, "book.docx") //先将转换的文件储存到临时目录 - tempOutputPath := filepath.Join(os.TempDir(), sessionId, m.Identify,"source") //filepath.Abs(filepath.Join("cache", sessionId)) - - sourceDir := strings.TrimSuffix(tempOutputPath,"source"); + tempOutputPath := filepath.Join(os.TempDir(), sessionId, m.Identify, "source") //filepath.Abs(filepath.Join("cache", sessionId)) + sourceDir := strings.TrimSuffix(tempOutputPath, "source"); if filetil.FileExists(sourceDir) { if err := os.RemoveAll(sourceDir); err != nil { - beego.Error("删除临时目录失败 ->", sourceDir , err) + beego.Error("删除临时目录失败 ->", sourceDir, err) } } if err := os.MkdirAll(outputPath, 0766); err != nil { - beego.Error("创建目录失败 => ",outputPath,err) + beego.Error("创建目录失败 -> ", outputPath, err) } - if err := os.MkdirAll(tempOutputPath, 0766);err != nil { - beego.Error("创建目录失败 => ",tempOutputPath,err) + if err := os.MkdirAll(tempOutputPath, 0766); err != nil { + beego.Error("创建目录失败 -> ", tempOutputPath, err) } - os.MkdirAll(filepath.Join(tempOutputPath,"Images"),0755) + os.MkdirAll(filepath.Join(tempOutputPath, "Images"), 0755) //defer os.RemoveAll(strings.TrimSuffix(tempOutputPath,"source")) - if filetil.FileExists(pdfpath) && filetil.FileExists(epubpath) && filetil.FileExists(mobipath) && filetil.FileExists(docxpath) { convertBookResult.EpubPath = epubpath convertBookResult.MobiPath = mobipath @@ -379,43 +379,43 @@ func (m *BookResult) Converter(sessionId string) (ConvertBookResult, error) { doc.Find("img").Each(func(i int, contentSelection *goquery.Selection) { if src, ok := contentSelection.Attr("src"); ok { //var encodeString string - dstSrcString := "Images/" + filepath.Base(src) + dstSrcString := "Images/" + filepath.Base(src) //如果是本地路径则直接读取文件内容 if strings.HasPrefix(src, "/") { spath := filepath.Join(conf.WorkingDirectory, src) - if filetil.CopyFile(spath,filepath.Join(tempOutputPath,dstSrcString));err != nil { - beego.Error("复制图片失败 -> ",err,src) + if filetil.CopyFile(spath, filepath.Join(tempOutputPath, dstSrcString)); err != nil { + beego.Error("复制图片失败 -> ", err, src) return } //if ff, e := ioutil.ReadFile(spath); e == nil { // encodeString = base64.StdEncoding.EncodeToString(ff) //} - }else{ + } else { client := &http.Client{} - if req,err := http.NewRequest("GET",src,nil); err == nil { - req.Header.Set("User-Agent","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36") - req.Header.Set("Referer",src) + if req, err := http.NewRequest("GET", src, nil); err == nil { + req.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36") + req.Header.Set("Referer", src) //10秒连接超时时间 client.Timeout = time.Second * 100 - if resp ,err := client.Do(req);err == nil { + if resp, err := client.Do(req); err == nil { defer resp.Body.Close() - if body, err := ioutil.ReadAll(resp.Body);err == nil { + if body, err := ioutil.ReadAll(resp.Body); err == nil { //encodeString = base64.StdEncoding.EncodeToString(body) - if err := ioutil.WriteFile(filepath.Join(tempOutputPath,dstSrcString),body,0755);err != nil { - beego.Error("下载图片失败 -> ",err,src) + if err := ioutil.WriteFile(filepath.Join(tempOutputPath, dstSrcString), body, 0755); err != nil { + beego.Error("下载图片失败 -> ", err, src) return } - }else{ - beego.Error("下载图片失败 -> ",err,src) + } else { + beego.Error("下载图片失败 -> ", err, src) return } - }else{ - beego.Error("下载图片失败 -> ",err,src) + } else { + beego.Error("下载图片失败 -> ", err, src) return } } @@ -440,54 +440,54 @@ func (m *BookResult) Converter(sessionId string) (ConvertBookResult, error) { } if err := filetil.CopyFile(filepath.Join(conf.WorkingDirectory, "static", "css", "kancloud.css"), filepath.Join(tempOutputPath, "styles", "css", "kancloud.css")); err != nil { - beego.Error("复制CSS样式出错 => static/css/kancloud.css",err) + beego.Error("复制CSS样式出错 -> static/css/kancloud.css", err) } - if err := filetil.CopyFile(filepath.Join(conf.WorkingDirectory, "static", "css", "export.css"), filepath.Join(tempOutputPath, "styles", "css", "export.css"));err != nil { - beego.Error("复制CSS样式出错 => static/css/export.css",err) + if err := filetil.CopyFile(filepath.Join(conf.WorkingDirectory, "static", "css", "export.css"), filepath.Join(tempOutputPath, "styles", "css", "export.css")); err != nil { + beego.Error("复制CSS样式出错 -> static/css/export.css", err) } - if err := filetil.CopyFile(filepath.Join(conf.WorkingDirectory, "static", "editor.md", "css", "editormd.preview.css"), filepath.Join(tempOutputPath, "styles", "editor.md", "css", "editormd.preview.css"));err != nil { - beego.Error("复制CSS样式出错 => static/editor.md/css/editormd.preview.css",err) + if err := filetil.CopyFile(filepath.Join(conf.WorkingDirectory, "static", "editor.md", "css", "editormd.preview.css"), filepath.Join(tempOutputPath, "styles", "editor.md", "css", "editormd.preview.css")); err != nil { + beego.Error("复制CSS样式出错 -> static/editor.md/css/editormd.preview.css", err) } if err := filetil.CopyFile(filepath.Join(conf.WorkingDirectory, "static", "prettify", "themes", "prettify.css"), filepath.Join(tempOutputPath, "styles", "prettify", "themes", "prettify.css")); err != nil { - beego.Error("复制CSS样式出错 => static/prettify/themes/prettify.css",err) + beego.Error("复制CSS样式出错 -> static/prettify/themes/prettify.css", err) } - if err := filetil.CopyFile(filepath.Join(conf.WorkingDirectory, "static", "css", "markdown.preview.css"), filepath.Join(tempOutputPath, "styles", "css", "markdown.preview.css"));err != nil { - beego.Error("复制CSS样式出错 => static/css/markdown.preview.css",err) + if err := filetil.CopyFile(filepath.Join(conf.WorkingDirectory, "static", "css", "markdown.preview.css"), filepath.Join(tempOutputPath, "styles", "css", "markdown.preview.css")); err != nil { + beego.Error("复制CSS样式出错 -> static/css/markdown.preview.css", err) } if err := filetil.CopyFile(filepath.Join(conf.WorkingDirectory, "static", "highlight", "styles", "vs.css"), filepath.Join(tempOutputPath, "styles", "highlight", "styles", "vs.css")); err != nil { - beego.Error("复制CSS样式出错 => static/highlight/styles/vs.css",err) + beego.Error("复制CSS样式出错 -> static/highlight/styles/vs.css", err) } if err := filetil.CopyFile(filepath.Join(conf.WorkingDirectory, "static", "katex", "katex.min.css"), filepath.Join(tempOutputPath, "styles", "katex", "katex.min.css")); err != nil { - beego.Error("复制CSS样式出错 => static/katex/katex.min.css",err) + beego.Error("复制CSS样式出错 -> static/katex/katex.min.css", err) } eBookConverter := &converter.Converter{ BasePath: tempOutputPath, - OutputPath: filepath.Join(strings.TrimSuffix(tempOutputPath, "source"),"output"), + OutputPath: filepath.Join(strings.TrimSuffix(tempOutputPath, "source"), "output"), Config: ebookConfig, Debug: true, ProcessNum: conf.GetExportProcessNum(), } - os.MkdirAll(eBookConverter.OutputPath,0766) + os.MkdirAll(eBookConverter.OutputPath, 0766) if err := eBookConverter.Convert(); err != nil { - beego.Error("转换文件错误:" + m.BookName + " => " + err.Error()) + beego.Error("转换文件错误:" + m.BookName + " -> " + err.Error()) return convertBookResult, err } beego.Info("文档转换完成:" + m.BookName) - if err := filetil.CopyFile(filepath.Join(eBookConverter.OutputPath,"output", "book.mobi"),mobipath,);err != nil { - beego.Error("复制文档失败 => ",filepath.Join(eBookConverter.OutputPath,"output", "book.mobi"),err) + if err := filetil.CopyFile(filepath.Join(eBookConverter.OutputPath, "output", "book.mobi"), mobipath, ); err != nil { + beego.Error("复制文档失败 -> ", filepath.Join(eBookConverter.OutputPath, "output", "book.mobi"), err) } - if err := filetil.CopyFile(filepath.Join(eBookConverter.OutputPath,"output", "book.pdf"),pdfpath);err != nil { - beego.Error("复制文档失败 => ",filepath.Join(eBookConverter.OutputPath,"output", "book.pdf"),err) + if err := filetil.CopyFile(filepath.Join(eBookConverter.OutputPath, "output", "book.pdf"), pdfpath); err != nil { + beego.Error("复制文档失败 -> ", filepath.Join(eBookConverter.OutputPath, "output", "book.pdf"), err) } - if err := filetil.CopyFile(filepath.Join(eBookConverter.OutputPath,"output", "book.epub"),epubpath); err != nil{ - beego.Error("复制文档失败 => ",filepath.Join(eBookConverter.OutputPath,"output", "book.epub"),err) + if err := filetil.CopyFile(filepath.Join(eBookConverter.OutputPath, "output", "book.epub"), epubpath); err != nil { + beego.Error("复制文档失败 -> ", filepath.Join(eBookConverter.OutputPath, "output", "book.epub"), err) } - if err := filetil.CopyFile(filepath.Join(eBookConverter.OutputPath,"output", "book.docx"),docxpath); err != nil { - beego.Error("复制文档失败 => ",filepath.Join(eBookConverter.OutputPath,"output", "book.docx"),err) + if err := filetil.CopyFile(filepath.Join(eBookConverter.OutputPath, "output", "book.docx"), docxpath); err != nil { + beego.Error("复制文档失败 -> ", filepath.Join(eBookConverter.OutputPath, "output", "book.docx"), err) } convertBookResult.MobiPath = mobipath @@ -508,24 +508,23 @@ func (m *BookResult) ExportMarkdown(sessionId string) (string, error) { defer os.RemoveAll(tempOutputPath) - bookUrl := conf.URLFor("DocumentController.Index",":key" , m.Identify) + "/" + bookUrl := conf.URLFor("DocumentController.Index", ":key", m.Identify) + "/" - err := exportMarkdown(tempOutputPath, 0, m.BookId,tempOutputPath,bookUrl) + err := exportMarkdown(tempOutputPath, 0, m.BookId, tempOutputPath, bookUrl) if err != nil { return "", err } - if err := ziptil.Compress(outputPath, tempOutputPath); err != nil { - beego.Error("导出Markdown失败=>", err) + beego.Error("导出Markdown失败->", err) return "", err } return outputPath, nil } //递归导出Markdown文档 -func exportMarkdown(p string, parentId int, bookId int,baseDir string,bookUrl string) error { +func exportMarkdown(p string, parentId int, bookId int, baseDir string, bookUrl string) error { o := orm.NewOrm() var docs []*Document @@ -533,7 +532,7 @@ func exportMarkdown(p string, parentId int, bookId int,baseDir string,bookUrl st _, err := o.QueryTable(NewDocument().TableNameWithPrefix()).Filter("book_id", bookId).Filter("parent_id", parentId).All(&docs) if err != nil { - beego.Error("导出Markdown失败=>", err) + beego.Error("导出Markdown失败->", err) return err } for _, doc := range docs { @@ -541,7 +540,7 @@ func exportMarkdown(p string, parentId int, bookId int,baseDir string,bookUrl st subDocCount, err := o.QueryTable(NewDocument().TableNameWithPrefix()).Filter("parent_id", doc.DocumentId).Count() if err != nil { - beego.Error("导出Markdown失败=>", err) + beego.Error("导出Markdown失败->", err) return err } @@ -555,9 +554,9 @@ func exportMarkdown(p string, parentId int, bookId int,baseDir string,bookUrl st } } else { if doc.Identify != "" { - if strings.HasSuffix(doc.Identify,".md") || strings.HasSuffix(doc.Identify,".markdown") { + if strings.HasSuffix(doc.Identify, ".md") || strings.HasSuffix(doc.Identify, ".markdown") { docPath = filepath.Join(p, doc.Identify) - }else { + } else { docPath = filepath.Join(p, doc.Identify+".md") } } else { @@ -610,35 +609,35 @@ func exportMarkdown(p string, parentId int, bookId int,baseDir string,bookUrl st originalLink := links[0][2] //如果当前链接位于当前项目内 - if strings.HasPrefix(originalLink,bookUrl) { + if strings.HasPrefix(originalLink, bookUrl) { docIdentify := strings.TrimSpace(strings.TrimPrefix(originalLink, bookUrl)) tempDoc := NewDocument() - if id,err := strconv.Atoi(docIdentify);err == nil && id > 0 { - err := o.QueryTable(NewDocument().TableNameWithPrefix()).Filter("document_id",id).One(tempDoc,"identify","parent_id","document_id") + if id, err := strconv.Atoi(docIdentify); err == nil && id > 0 { + err := o.QueryTable(NewDocument().TableNameWithPrefix()).Filter("document_id", id).One(tempDoc, "identify", "parent_id", "document_id") if err != nil { beego.Error(err) return link } - }else{ - err := o.QueryTable(NewDocument().TableNameWithPrefix()).Filter("identify",docIdentify).One(tempDoc,"identify","parent_id","document_id") + } else { + err := o.QueryTable(NewDocument().TableNameWithPrefix()).Filter("identify", docIdentify).One(tempDoc, "identify", "parent_id", "document_id") if err != nil { beego.Error(err) return link } } - tempLink := recursiveJoinDocumentIdentify(tempDoc.ParentId,"") + strings.TrimPrefix(originalLink, bookUrl) + tempLink := recursiveJoinDocumentIdentify(tempDoc.ParentId, "") + strings.TrimPrefix(originalLink, bookUrl) - if !strings.HasSuffix(tempLink,".md") && !strings.HasSuffix(doc.Identify,".markdown") { + if !strings.HasSuffix(tempLink, ".md") && !strings.HasSuffix(doc.Identify, ".markdown") { tempLink = tempLink + ".md" } - relative := strings.TrimPrefix(strings.Replace(p,"\\","/",-1),strings.Replace(baseDir,"\\","/",-1)) + relative := strings.TrimPrefix(strings.Replace(p, "\\", "/", -1), strings.Replace(baseDir, "\\", "/", -1)) repeat := 0 if relative != "" { - relative = strings.TrimSuffix(strings.TrimPrefix(relative,"/"),"/") - repeat = strings.Count(relative,"/") + 1 + relative = strings.TrimSuffix(strings.TrimPrefix(relative, "/"), "/") + repeat = strings.Count(relative, "/") + 1 } - beego.Info(repeat,"|",relative,"|",p,"|",baseDir) - tempLink = strings.Repeat("../",repeat) + tempLink + beego.Info(repeat, "|", relative, "|", p, "|", baseDir) + tempLink = strings.Repeat("../", repeat) + tempLink link = strings.TrimSuffix(link, originalLink+")") + tempLink + ")" } @@ -647,16 +646,16 @@ func exportMarkdown(p string, parentId int, bookId int,baseDir string,bookUrl st return link }) - }else{ + } else { markdown = "# " + doc.DocumentName + "\n" } if err := ioutil.WriteFile(docPath, []byte(markdown), 0644); err != nil { - beego.Error("导出Markdown失败=>", err) + beego.Error("导出Markdown失败->", err) return err } if subDocCount > 0 { - if err = exportMarkdown(dirPath, doc.DocumentId, bookId,baseDir,bookUrl); err != nil { + if err = exportMarkdown(dirPath, doc.DocumentId, bookId, baseDir, bookUrl); err != nil { return err } } @@ -664,12 +663,12 @@ func exportMarkdown(p string, parentId int, bookId int,baseDir string,bookUrl st return nil } -func recursiveJoinDocumentIdentify(parentDocId int,identify string) string { +func recursiveJoinDocumentIdentify(parentDocId int, identify string) string { o := orm.NewOrm() doc := NewDocument() - err := o.QueryTable(NewDocument().TableNameWithPrefix()).Filter("document_id",parentDocId).One(doc,"identify","parent_id","document_id") + err := o.QueryTable(NewDocument().TableNameWithPrefix()).Filter("document_id", parentDocId).One(doc, "identify", "parent_id", "document_id") if err != nil { beego.Error(err) @@ -678,11 +677,11 @@ func recursiveJoinDocumentIdentify(parentDocId int,identify string) string { if doc.Identify == "" { identify = strconv.Itoa(doc.DocumentId) + "/" + identify - }else{ + } else { identify = doc.Identify + "/" + identify } if doc.ParentId > 0 { - identify = recursiveJoinDocumentIdentify(doc.ParentId,identify) + identify = recursiveJoinDocumentIdentify(doc.ParentId, identify) } return identify } @@ -698,4 +697,3 @@ func (m *BookResult) FindFirstDocumentByBookId(bookId int) (*Document, error) { return doc, err } - diff --git a/models/DocumentTree.go b/models/DocumentTree.go index 6e05d904..8af4d089 100644 --- a/models/DocumentTree.go +++ b/models/DocumentTree.go @@ -17,8 +17,8 @@ type DocumentTree struct { Identify string `json:"identify"` BookIdentify string `json:"-"` Version int64 `json:"version"` - State *DocumentSelected `json:"state,omitempty"` - AAttrs map[string]interface{} `json:"a_attr"` + State *DocumentSelected `json:"-"` + AAttrs map[string]interface{} `json:"-"` } type DocumentSelected struct { Selected bool `json:"selected"` diff --git a/static/css/main.css b/static/css/main.css index bc02c47d..41daece2 100644 --- a/static/css/main.css +++ b/static/css/main.css @@ -423,6 +423,7 @@ textarea{ margin: 0 15px; padding: 10px 20px; line-height: 25px; + word-break: break-word; } .manual-search-reader .search-item:hover{ background-color: #F5F5F5; diff --git a/static/js/array.js b/static/js/array.js new file mode 100644 index 00000000..78608df4 --- /dev/null +++ b/static/js/array.js @@ -0,0 +1,32 @@ +/** + * 删除数组中的匹配值 + * @param $callback + */ +Array.prototype.remove = function ($callback) { + var $isFunction = typeof $callback === "function"; + + var arr = []; + for(var $i = 0,$len = this.length; $i < $len;$i ++){ + if($isFunction){ + if($callback(this[$i])){ + arr.push($i); + } + }else if(this[$i] == $callback){ + arr.push($i); + } + } + for($i = 0,$len = arr.length; $i < $len;$i++){ + this.slice($i,1); + } +}; +//格式化文件大小 +function formatBytes($size) { + if (typeof $size === "number") { + var $units = [" B", " KB", " MB", " GB", " TB"]; + + for ($i = 0; $size >= 1024 && $i < 4; $i++) $size /= 1024; + + return $size.toFixed(2) + $units[$i]; + } + return $size; +} diff --git a/static/js/editor.js b/static/js/editor.js index e412d564..09d281d6 100644 --- a/static/js/editor.js +++ b/static/js/editor.js @@ -1,6 +1,64 @@ /** * Created by lifei6671 on 2017/4/29 0029. */ + +/** + * 打开最后选中的节点 + */ +function openLastSelectedNode() { + //如果文档树或编辑器没有准备好则不加载文档 + if (window.treeCatalog == null || window.editor == null) { + return false; + } + var $isSelected = false; + if(window.localStorage){ + var $selectedNodeId = window.localStorage.getItem("MinDoc::LastLoadDocument:" + window.book.identify); + try{ + if($selectedNodeId){ + //遍历文档树判断是否存在节点 + $.each(window.documentCategory,function (i, n) { + if(n.id == $selectedNodeId && !$isSelected){ + var $node = {"id" : n.id}; + window.treeCatalog.deselect_all(); + window.treeCatalog.select_node($node); + $isSelected = true; + } + }); + + } + }catch($ex){ + console.log($ex) + } + } + + //如果节点不存在,则默认选中第一个节点 + if (!$isSelected && window.documentCategory.length > 0){ + var doc = window.documentCategory[0]; + + if(doc && doc.id > 0){ + var node = {"id": doc.id}; + $("#sidebar").jstree(true).select_node(node); + $isSelected = true; + } + } + return $isSelected; +} + +/** + * 设置最后选中的文档 + * @param $node + */ +function setLastSelectNode($node) { + if(window.localStorage) { + if (typeof $node === "undefined" || !$node) { + window.localStorage.removeItem("MinDoc::LastLoadDocument:" + window.book.identify); + } else { + var nodeId = $node.id ? $node.id : $node.node.id; + window.localStorage.setItem("MinDoc::LastLoadDocument:" + window.book.identify, nodeId); + } + } +} + /** * 保存排序 * @param node @@ -24,8 +82,6 @@ function jstree_save(node, parent) { shade: [0.1, '#fff'] //0.1透明度的白色背景 }); - console.log(JSON.stringify(nodeData)); - $.ajax({ url : window.sortURL, type :"post", @@ -88,6 +144,13 @@ function openDeleteDocumentDialog($node) { layer.close(index); if(res.errcode === 0){ window.treeCatalog.delete_node($node); + window.documentCategory.remove(function (item) { + return item.id == $node.id; + }); + + + // console.log(window.documentCategory) + setLastSelectNode(); }else{ layer.msg("删除失败",{icon : 2}) } @@ -153,10 +216,9 @@ function pushDocumentCategory($node) { function pushVueLists($lists) { window.vueApp.lists = []; - for(var j in $lists){ - var item = $lists[j]; + $.each($lists,function (i, item) { window.vueApp.lists.push(item); - } + }); } /** @@ -245,14 +307,6 @@ window.documentHistory = function() { } }); }; -//格式化文件大小 -function formatBytes($size) { - var $units = [" B", " KB", " MB", " GB", " TB"]; - - for ($i = 0; $size >= 1024 && $i < 4; $i++) $size /= 1024; - - return $size.toFixed(2) + $units[$i]; -} function uploadImage($id,$callback) { /** 粘贴上传图片 **/ @@ -370,5 +424,26 @@ $(function () { } } }); + /** + * 启动自动保存,默认30s自动保存一次 + */ + if(window.book.auto_save){ + setTimeout(function () { + setInterval(function () { + var $then = $("#markdown-save"); + if(!window.saveing && $then.hasClass("change")){ + $then.trigger("click"); + } + },30000); + },30000); + } + /** + * 当离开窗口时存在未保存的文档会提示保存 + */ + $(window).on("beforeunload",function () { + if($("#markdown-save").hasClass("change")){ + return '您输入的内容尚未保存,确定离开此页面吗?'; + } + }); +}); -}); \ No newline at end of file diff --git a/static/js/kancloud.js b/static/js/kancloud.js index 12100c99..1791e481 100644 --- a/static/js/kancloud.js +++ b/static/js/kancloud.js @@ -1,6 +1,7 @@ var events = function () { var articleOpen = function (event, $param) { - + //当打开文档时,将文档ID加入到本地缓存。 + window.localStorage && window.localStorage.setItem("MinDoc::LastLoadDocument:" + window.book.identify, $param.$id); var prevState = window.history.state || {}; if ('pushState' in history) { diff --git a/static/js/markdown.js b/static/js/markdown.js index e3593849..6d9983f5 100644 --- a/static/js/markdown.js +++ b/static/js/markdown.js @@ -43,18 +43,8 @@ $(function () { }; this.addKeyMap(keyMap); - var $select_node_id = window.treeCatalog.get_selected(); - if ($select_node_id) { - var $select_node = window.treeCatalog.get_node($select_node_id[0]) - if ($select_node) { - $select_node.node = { - id: $select_node.id - }; - - loadDocument($select_node); - } - } - + //如果没有选中节点则选中默认节点 + openLastSelectedNode(); uploadImage("docEditor", function ($state, $res) { if ($state === "before") { return layer.load(1, { @@ -67,6 +57,7 @@ $(function () { } } }); + }, onchange: function () { resetEditorChanged(true); @@ -164,6 +155,7 @@ $(function () { pushDocumentCategory(node); window.selectNode = node; pushVueLists(res.data.attach); + setLastSelectNode($node); } else { layer.msg("文档加载失败"); } @@ -202,6 +194,7 @@ $(function () { $.ajax({ beforeSend: function () { index = layer.load(1, { shade: [0.1, '#fff'] }); + window.saveing = true; }, url: window.editURL, data: { "identify": window.book.identify, "doc_id": doc_id, "markdown": content, "html": html, "cover": $is_cover ? "yes" : "no", "version": version }, @@ -212,6 +205,7 @@ $(function () { layer.close(index); if (res.errcode === 0) { resetEditorChanged(false); + window.saveing = false; for (var i in window.documentCategory) { var item = window.documentCategory[i]; @@ -223,6 +217,7 @@ $(function () { if (typeof callback === "function") { callback(); } + } else if(res.errcode === 6005) { var confirmIndex = layer.confirm('文档已被其他人修改确定覆盖已存在的文档吗?', { btn: ['确定', '取消'] // 按钮 @@ -237,6 +232,7 @@ $(function () { error : function (XMLHttpRequest, textStatus, errorThrown) { layer.close(index); layer.msg("服务器错误:" + errorThrown); + window.saveing = false; } }); } @@ -357,8 +353,11 @@ $(function () { } } } - }).on('loaded.jstree', function () { - window.treeCatalog = $(this).jstree(); + }).on("ready.jstree",function () { + window.treeCatalog = $("#sidebar").jstree(true); + + //如果没有选中节点则选中默认节点 + // openLastSelectedNode(); }).on('select_node.jstree', function (node, selected, event) { if ($("#markdown-save").hasClass('change')) { @@ -371,7 +370,9 @@ $(function () { } loadDocument(selected); - }).on("move_node.jstree", jstree_save); + }).on("move_node.jstree", jstree_save).on("delete_node.jstree",function($node,$parent) { + openLastSelectedNode(); + }); /** * 打开文档模板 */ diff --git a/views/book/setting.tpl b/views/book/setting.tpl index de758838..df478276 100644 --- a/views/book/setting.tpl +++ b/views/book/setting.tpl @@ -158,7 +158,15 @@
- + +
+
+ +
+ +
+
+
@@ -325,7 +333,7 @@ }).on("show.bs.modal",function () { window.modalHtml = $("#upload-logo-panel").find(".modal-body").html(); }); - $("#autoRelease,#enableShare,#isDownload,#is_use_first_document").bootstrapSwitch(); + $("#autoRelease,#enableShare,#isDownload,#isUseFirstDocument,#autoSave").bootstrapSwitch(); $('input[name="label"]').tagsinput({ confirmKeys: [13,44], diff --git a/views/document/default_read.tpl b/views/document/default_read.tpl index cb585324..b609e18c 100644 --- a/views/document/default_read.tpl +++ b/views/document/default_read.tpl @@ -27,13 +27,7 @@ - - - - +
diff --git a/views/document/markdown_edit_template.tpl b/views/document/markdown_edit_template.tpl index 44029593..ebbeaaa4 100644 --- a/views/document/markdown_edit_template.tpl +++ b/views/document/markdown_edit_template.tpl @@ -7,7 +7,9 @@ 编辑文档 - Powered by MinDoc