diff --git a/Booklet/build/debug/main.js b/Booklet/build/debug/main.js index 1a28efa..045fba1 100644 --- a/Booklet/build/debug/main.js +++ b/Booklet/build/debug/main.js @@ -11,9 +11,11 @@ me = this; this.tree = this.find("toc-ui"); this.currentToc = void 0; + this.emux = false; this.on("treeselect", function(e) { + console.log(e.treepath); if ((me.currentToc === e) || (e === void 0) || (e.treepath === 0)) { - return; + return me.reloadEditor(); } return me.open(e); }); @@ -32,6 +34,9 @@ return m.show(e); }; return this.editor.codemirror.on("change", function() { + if (me.emux) { + return; + } if (!me.currentToc) { return; } @@ -45,7 +50,8 @@ return this.error(__("No book selected")); } ch = new BookletChapter(this.book); - return this.displayToc(); + this.displayToc(); + return ch.treepath = ch.path; } newSection() { @@ -54,7 +60,8 @@ return this.error(__("No chapter selected")); } sec = new BookletSection(this.currentToc); - return this.displayToc(); + this.displayToc(); + return sec.treepath = sec.path; } newFile() { @@ -63,7 +70,28 @@ return this.error(__("No section selected")); } file = new BookletFile(this.currentToc); - return this.displayToc(); + this.displayToc(); + return file.treepath = file.path; + } + + delete() { + var fn, me; + me = this; + if (!this.currentToc) { + return this.error(__("No entrie select")); + } + fn = function() { + me.currentToc = void 0; + me.displayToc(); + return me.reloadEditor(); + }; + return this.currentToc.remove().then(function() { + me.notify(__("Entrie deleted")); + return fn(); + }).catch(function(e) { + me.error(e); + return fn(); + }); } contextMenu() { @@ -79,7 +107,7 @@ }, { text: __("Delete book"), - dataid: "deleteBook" + dataid: "delete" } ]; case "chapter": @@ -90,7 +118,7 @@ }, { text: __("Delete chapter"), - dataid: "deleteChapter" + dataid: "delete" } ]; case "section": @@ -101,7 +129,14 @@ }, { text: __("Delete section"), - dataid: "deleteSection" + dataid: "delete" + } + ]; + case "file": + return [ + { + text: __("Delete file"), + dataid: "delete" } ]; } @@ -247,15 +282,28 @@ } }); case `${this.name}-Save`: - return me.book.save(me); + if (!me.book) { + return; + } + if (me.currentToc) { + me.saveContext(); + } + me.displayToc(); + return me.book.save().then(function() { + return me.notify(__("Book saved")); + }).catch(function(e) { + return me.error(__("Can't save the book : {0}", e)); + }); } } open(toc) { + this.emux = true; this.saveContext(); this.currentToc = toc; this.reloadEditor(); - return this.displayToc(); + this.displayToc(); + return this.emux = false; } newAt(folder) { @@ -294,13 +342,48 @@ if (!this.descFile.dirty) { return this.name; } - t = (new RegExp("^\s*#+(.*)[\n,$]", "g")).exec(this.descFile.cache); + t = (new RegExp("^\s*#+(.*)\n", "g")).exec(this.descFile.cache); if (!(t && t.length === 2)) { return this.name; } return this.name = t[1].trim(); } + remove() { + var me; + me = this; + return new Promise(function(r, e) { + var f; + f = me.path.asFileHandler(); + return f.meta(function(d) { + if (d.error) { + if (!me.parent) { + return r(); + } + return me.parent.removeChild(me).then(function() { + return r(); + }).catch(function(msg) { + return e(msg); + }); + } else { + return f.remove(function(ret) { + if (ret.error) { + return e(ret.error); + } + if (!me.parent) { + return r(); + } + return me.parent.removeChild(me).then(function() { + return r(); + }).catch(function(msg) { + return e(msg); + }); + }); + } + }); + }); + } + }; BookletFolder = class BookletFolder extends BookletEntry { @@ -309,16 +392,43 @@ this.type = type; this.path = path1; this.hasMeta = hasMeta; + this.cnt = 0; this.nodes = []; if (this.hasMeta) { this.metaFile = `${this.path}/meta.json`.asFileHandler(); } - this.descFile = `${this.path}/${this.type}.md`.asFileHandler(); + this.descFile = `${this.path}/INTRO.md`.asFileHandler(); } add(chap) { chap.parent = this; - return this.nodes.push(chap); + this.nodes.push(chap); + if (this.hasMeta && this.metaFile) { + this.metaFile.dirty = true; + } + if (chap.metaFile && chap.hasMeta) { + chap.metaFile.dirty = true; + } + return this.cnt = this.cnt + 1; + } + + removeChild(child) { + var me; + me = this; + //v.treepath = v.path for v in @nodes if @nodes + return new Promise(function(r, e) { + me.nodes.splice(me.nodes.indexOf(child), 1); + if (!(me.hasMeta && me.metaFile)) { + //if me.nodes.includes child + return r(); + } + me.metaFile.dirty = true; + return me.updateMeta().then(function() { + return r(); + }).catch(function(msg) { + return e(msg); + }); + }); } size() { @@ -328,7 +438,6 @@ mkdir() { var me; me = this; - console.log("making:" + me.path); return new Promise(function(r, e) { var dir; dir = me.path.asFileHandler(); @@ -355,14 +464,13 @@ return new Promise(function(r, e) { var i, j, len, list, ref, v; list = []; - if (me.hasMeta) { + if (me.type !== 'section') { ref = me.nodes; for (i = j = 0, len = ref.length; j < len; i = ++j) { v = ref[i]; list[i] = v; } } - console.log(list); return me.mkdir().then(function() { var fn; fn = function(l) { @@ -373,18 +481,94 @@ el = (l.splice(0, 1))[0]; return el.mkdirs().then(function() { return fn(l); + }).catch(function(msg) { + return e(msg); }); }; return fn(list); + }).catch(function(msg) { + return e(msg); }); }); } - save(handle) { - return this.mkdirs().then(function() { - return handle.notify(__("All directories are created")); - }).catch(function(msg) { - return handle.error(msg); + updateMeta() { + var me; + me = this; + return new Promise(function(r, e) { + var entries, i, j, len, ref, v; + if (!me.metaFile.dirty) { + return r(); + } + entries = []; + ref = me.nodes; + for (i = j = 0, len = ref.length; j < len; i = ++j) { + v = ref[i]; + entries[i] = v.path; + } + me.metaFile.cache = entries; + return me.metaFile.write("object", function(d) { + if (d.error) { + return e(d.error); + } + me.metaFile.dirty = false; + console.log("saved " + me.metaFile.path); + return r(); + }); + }); + } + + update() { + var me; + me = this; + return new Promise(function(r, e) { + return me.updateMeta().then(function() { + if (!me.descFile.dirty) { + return r(); + } + return me.descFile.write("text/plain", function(d) { + if (d.error) { + return e(d.error); + } + me.descFile.dirty = false; + console.log("saved " + me.descFile.path); + return r(); + }); + }).catch(function(msg) { + return e(msg); + }); + }); + } + + updateAll() { + var me; + me = this; + return new Promise(function(r, e) { + var i, j, len, list, ref, v; + list = []; + ref = me.nodes; + for (i = j = 0, len = ref.length; j < len; i = ++j) { + v = ref[i]; + list[i] = v; + } + return me.update().then(function() { + var fn; + fn = function(l) { + var el; + if (l.length === 0) { + return r(); + } + el = (l.splice(0, 1))[0]; + return el.updateAll().then(function() { + return fn(l); + }).catch(function(msg) { + return e(msg); + }); + }; + return fn(list); + }).catch(function(msg) { + return e(msg); + }); }); } @@ -399,8 +583,6 @@ return this; } - remove(apif) {} - }; Book = class Book extends BookletFolder { @@ -408,12 +590,28 @@ super('book', path, true); } + save() { + var me; + me = this; + return new Promise(function(r, e) { + return me.mkdirs().then(function() { + return me.updateAll().then(function() { + return r(); + }).catch(function(msg) { + return e(msg); + }); + }).catch(function(msg) { + return e(msg); + }); + }); + } + }; BookletChapter = class BookletChapter extends BookletFolder { constructor(book) { var path; - path = `${book.path}/c_${book.size()}`; + path = `${book.path}/c_${book.cnt}`; super('chapter', path, true); book.add(this); } @@ -423,8 +621,8 @@ BookletSection = class BookletSection extends BookletFolder { constructor(chapter) { var path; - path = `${chapter.path}/s_${chapter.size()}`; - super("section", path, false); + path = `${chapter.path}/s_${chapter.cnt}`; + super("section", path, true); chapter.add(this); } @@ -434,28 +632,29 @@ constructor(section) { super(); this.section = section; - this.section.add(this); - this.path = `${this.section.path}/f_${this.section.size()}.md`; + this.hasMeta = false; + this.type = "file"; + this.path = `${this.section.path}/f_${this.section.cnt}.md`; this.descFile = this.path.asFileHandler(); + this.section.add(this); } - save(handle) { - var j, len, me, ref, v; - ref = this.sections; - for (j = 0, len = ref.length; j < len; j++) { - v = ref[j]; - v.save(this.descFile); - } + updateAll() { + var me; me = this; - if (this.descFile.dirty) { - return this.descFile.write("text/plain", function(r) { - if (r.error) { - handle.error(__("Fail to save file {0}: {1}", me.descFile.path, r.error)); + return new Promise(function(r, e) { + if (!me.descFile.dirty) { + return r(); + } + return me.descFile.write("text/plain", function(d) { + if (d.error) { + return e(d.error); } - this.descFile.dirty = false; - return handle.notify(__("Book saved")); + me.descFile.dirty = false; + console.log("saved" + me.descFile.path); + return r(); }); - } + }); } toc() { diff --git a/Booklet/coffees/common.coffee b/Booklet/coffees/common.coffee index 8d1a2d2..e922b65 100644 --- a/Booklet/coffees/common.coffee +++ b/Booklet/coffees/common.coffee @@ -11,28 +11,62 @@ class BookletEntry updateName:() -> return @name unless @descFile.dirty - t = (new RegExp "^\s*#+(.*)[\n,$]", "g").exec @descFile.cache + t = (new RegExp "^\s*#+(.*)\n", "g").exec @descFile.cache return @name unless t and t.length is 2 @name = t[1].trim() - + + remove: () -> + me = @ + return new Promise (r, e) -> + f = me.path.asFileHandler() + f.meta (d) -> + if d.error + return r() unless me.parent + return me.parent.removeChild(me).then () -> + r() + .catch (msg) -> e msg + else + f.remove (ret) -> + return e ret.error if ret.error + return r() unless me.parent + me.parent.removeChild(me).then () -> + r() + .catch (msg) -> e msg class BookletFolder extends BookletEntry constructor: (@type, @path, @hasMeta) -> super() + @cnt = 0 @nodes = [] @metaFile = "#{@path}/meta.json".asFileHandler() if @hasMeta - @descFile = "#{@path}/#{@type}.md".asFileHandler() + @descFile = "#{@path}/INTRO.md".asFileHandler() add: (chap) -> chap.parent = @ @nodes.push chap + @metaFile.dirty = true if @hasMeta and @metaFile + chap.metaFile.dirty = true if chap.metaFile and chap.hasMeta + @cnt = @cnt + 1 + + removeChild: (child) -> + me = @ + #v.treepath = v.path for v in @nodes if @nodes + return new Promise (r, e) -> + me.nodes.splice (me.nodes.indexOf child), 1 + #if me.nodes.includes child + return r() unless me.hasMeta and me.metaFile + me.metaFile.dirty = true + me.updateMeta().then () -> + r() + .catch (msg) -> + e msg + size: () -> return @nodes.length mkdir: () -> me = @ - console.log "making:" + me.path return new Promise (r, e) -> dir = me.path.asFileHandler() dir.meta (d) -> @@ -47,66 +81,113 @@ class BookletFolder extends BookletEntry me = @ return new Promise (r, e) -> list = [] - list[i] = v for v, i in me.nodes if me.hasMeta - console.log list + list[i] = v for v, i in me.nodes if me.type isnt 'section' me.mkdir().then () -> fn = (l) -> return r() if l.length is 0 el = (l.splice 0, 1)[0] el.mkdirs().then () -> fn l + .catch (msg) -> e msg return fn list + .catch (msg) -> e msg - save:(handle) -> - @mkdirs().then ()-> - handle.notify __("All directories are created") - .catch (msg) -> - handle.error msg + updateMeta: () -> + me = @ + return new Promise (r, e) -> + return r() unless me.metaFile.dirty + entries = [] + entries[i] = v.path for v,i in me.nodes + me.metaFile.cache = entries + me.metaFile.write "object", (d) -> + return e d.error if d.error + me.metaFile.dirty = false + console.log "saved " + me.metaFile.path + r() + + + update: () -> + me = @ + return new Promise (r, e) -> + me.updateMeta().then () -> + return r() unless me.descFile.dirty + me.descFile.write "text/plain", (d) -> + return e d.error if d.error + me.descFile.dirty = false + console.log "saved " + me.descFile.path + r() + .catch (msg) -> e msg + + + updateAll: () -> + me = @ + return new Promise (r, e) -> + list = [] + list[i] = v for v, i in me.nodes + me.update().then () -> + fn = (l) -> + return r() if l.length is 0 + el = (l.splice 0, 1)[0] + el.updateAll().then () -> + fn l + .catch (msg) -> e msg + return fn list + .catch (msg) -> e msg toc: () -> @updateName() v.toc() for v in @nodes @ - remove: (apif) -> - class Book extends BookletFolder constructor: (path) -> super 'book', path, true - + + save:() -> + me = @ + return new Promise (r, e) -> + me.mkdirs().then () -> + me.updateAll().then () -> + r() + .catch (msg) -> e msg + . catch (msg) -> e msg class BookletChapter extends BookletFolder constructor: (book) -> - path = "#{book.path}/c_#{book.size()}" + path = "#{book.path}/c_#{book.cnt}" super 'chapter', path, true book.add @ class BookletSection extends BookletFolder constructor: (chapter) -> - path = "#{chapter.path}/s_#{chapter.size()}" - super "section", path, false + path = "#{chapter.path}/s_#{chapter.cnt}" + super "section", path, true chapter.add @ class BookletFile extends BookletEntry constructor: (@section) -> super() - @section.add @ - @path = "#{@section.path}/f_#{@section.size()}.md" + @hasMeta = false + @type = "file" + @path = "#{@section.path}/f_#{@section.cnt}.md" @descFile = @path.asFileHandler() + @section.add @ - save: (handle) -> - v.save @descFile for v in @sections + updateAll: ()-> me = @ - if @descFile.dirty - @descFile.write "text/plain", (r) -> - handle.error __("Fail to save file {0}: {1}", me.descFile.path, r.error) if r.error - @descFile.dirty = false - handle.notify __("Book saved") + return new Promise (r, e) -> + return r() unless me.descFile.dirty + me.descFile.write "text/plain", (d) -> + return e d.error if d.error + me.descFile.dirty = false + console.log "saved" + me.descFile.path + r() + toc: () -> @updateName() @ \ No newline at end of file diff --git a/Booklet/coffees/main.coffee b/Booklet/coffees/main.coffee index ea041fc..d0a1145 100644 --- a/Booklet/coffees/main.coffee +++ b/Booklet/coffees/main.coffee @@ -6,8 +6,9 @@ class Booklet extends this.OS.GUI.BaseApplication me = @ @tree = @find "toc-ui" @currentToc = undefined + @emux = false @on "treeselect", (e) -> - return if (me.currentToc is e) or (e is undefined) or (e.treepath is 0) + return me.reloadEditor() if (me.currentToc is e) or (e is undefined) or (e.treepath is 0) me.open e @initEditor() @@ -20,6 +21,7 @@ class Booklet extends this.OS.GUI.BaseApplication me[evt.item.data.dataid]() m.show e @editor.codemirror.on "change", () -> + return if me.emux return unless me.currentToc me.currentToc.descFile.dirty = true @@ -27,34 +29,55 @@ class Booklet extends this.OS.GUI.BaseApplication return @error __("No book selected") unless @currentToc and @currentToc.type is "book" ch = new BookletChapter(@book) @displayToc() + ch.treepath = ch.path newSection: () -> return @error __("No chapter selected") unless @currentToc and @currentToc.type is "chapter" sec = new BookletSection(@currentToc) @displayToc() + sec.treepath = sec.path newFile: () -> return @error __("No section selected") unless @currentToc and @currentToc.type is "section" file = new BookletFile(@currentToc) @displayToc() - + file.treepath = file.path + + delete: () -> + me = @ + return @error __("No entrie select") unless @currentToc + fn = () -> + me.currentToc = undefined + me.displayToc() + me.reloadEditor() + @currentToc.remove().then () -> + me.notify __("Entrie deleted") + fn() + .catch (e) -> + me.error e + fn() + contextMenu: () -> return undefined unless @currentToc switch @currentToc.type when "book" return [ { text: __("New chapter"), dataid: "newChapter" }, - { text: __("Delete book"), dataid: "deleteBook" } + { text: __("Delete book"), dataid: "delete" } ] when "chapter" return [ { text: __("New section"), dataid: "newSection" }, - { text: __("Delete chapter"), dataid: "deleteChapter" } + { text: __("Delete chapter"), dataid: "delete" } ] when "section" return [ { text: __("New file"), dataid: "newFile" }, - { text: __("Delete section"), dataid: "deleteSection" } + { text: __("Delete section"), dataid: "delete" } + ] + when "file" + return [ + { text: __("Delete file"), dataid: "delete" } ] return undefined @@ -142,13 +165,24 @@ class Booklet extends this.OS.GUI.BaseApplication me.newAt "#{d}/#{f}" , __("Open file"), { mimes: ['dir'], file: { basename: __("BookName") }} when "#{@name}-Save" - me.book.save(me) + return unless me.book + me.saveContext() if me.currentToc + me.displayToc() + me.book.save().then () -> + me.notify __("Book saved") + .catch (e) -> + me.error __("Can't save the book : {0}", e) open: (toc) -> + @emux = true @saveContext() @currentToc = toc @reloadEditor() @displayToc() + @emux = false + + openBook: (metaFile) -> + newAt: (folder) -> @tree.set "selectedItem", false