diff --git a/Booklet/build/debug/main.js b/Booklet/build/debug/main.js index c94e500..1a28efa 100644 --- a/Booklet/build/debug/main.js +++ b/Booklet/build/debug/main.js @@ -11,15 +11,15 @@ me = this; this.tree = this.find("toc-ui"); this.currentToc = void 0; - this.tree.set("ontreeselect", function(e) { - me.saveContext(); - me.currfile = e.target.descFile; - me.reloadEditor(); - return me.currentToc = e; + this.on("treeselect", function(e) { + if ((me.currentToc === e) || (e === void 0) || (e.treepath === 0)) { + return; + } + return me.open(e); }); this.initEditor(); this.resizeContent(); - return this.tree.contextmenuHandler = function(e, m) { + this.tree.contextmenuHandler = function(e, m) { var menus; menus = me.contextMenu(); if (!menus) { @@ -31,10 +31,39 @@ }); return m.show(e); }; + return this.editor.codemirror.on("change", function() { + if (!me.currentToc) { + return; + } + return me.currentToc.descFile.dirty = true; + }); } newChapter() { - return console.log(this.currentToc); + var ch; + if (!(this.currentToc && this.currentToc.type === "book")) { + return this.error(__("No book selected")); + } + ch = new BookletChapter(this.book); + return this.displayToc(); + } + + newSection() { + var sec; + if (!(this.currentToc && this.currentToc.type === "chapter")) { + return this.error(__("No chapter selected")); + } + sec = new BookletSection(this.currentToc); + return this.displayToc(); + } + + newFile() { + var file; + if (!(this.currentToc && this.currentToc.type === "section")) { + return this.error(__("No section selected")); + } + file = new BookletFile(this.currentToc); + return this.displayToc(); } contextMenu() { @@ -84,7 +113,6 @@ markarea = this.find("markarea"); this.container = this.find("mycontainer"); this.previewOn = false; - this.currfile = "Untitled".asFileHandler(); this.editormux = false; me = this; this.editor = new SimpleMDE({ @@ -134,18 +162,28 @@ this.bindKey("ALT-N", function() { return me.actionFile(`${me.name}-New`); }); - return this.bindKey("ALT-O", function() { + this.bindKey("ALT-O", function() { return me.actionFile(`${me.name}-Open`); }); + return this.bindKey("CTRL-S", function() { + return me.actionFile(`${me.name}-Save`); + }); } reloadEditor() { - this.editor.value(this.currfile.cache); - return this.scheme.set("apptitle", `Booklet - ${this.currfile.basename}`); + if (this.currentToc === void 0) { + this.editor.value(""); + return this.scheme.set("apptitle", this.name); + } + this.editor.value(this.currentToc.descFile.cache || ""); + return this.scheme.set("apptitle", `Booklet - ${this.currentToc.descFile.path}`); } saveContext() { - return this.currfile.cache = this.editor.value(); + if (!this.currentToc) { + return; + } + return this.currentToc.descFile.cache = this.editor.value(); } resizeContent() { @@ -174,6 +212,11 @@ text: "__(Open a booklet)", dataid: `${this.name}-Open`, shortcut: "A-O" + }, + { + text: "__(Save a booklet)", + dataid: `${this.name}-Save`, + shortcut: "C-S" } ], onmenuselect: function(e) { @@ -190,31 +233,43 @@ switch (e) { case `${this.name}-Open`: return this.openDialog("FileDiaLog", function(d, f) { - return me.open(`${d}/${f}`.asFileHandler()); + return console.log(`${d}/${f}`.asFileHandler()); }, __("Open file"), { mimes: me.meta().mimes }); case `${this.name}-New`: return this.openDialog("FileDiaLog", function(d, f) { - return me.newAt(d); + return me.newAt(`${d}/${f}`); }, __("Open file"), { - mimes: ['dir'] + mimes: ['dir'], + file: { + basename: __("BookName") + } }); + case `${this.name}-Save`: + return me.book.save(me); } } - open(file) {} + open(toc) { + this.saveContext(); + this.currentToc = toc; + this.reloadEditor(); + return this.displayToc(); + } newAt(folder) { + this.tree.set("selectedItem", false); this.book = new Book(folder); + this.book.treepath = this.book.path; + this.currentToc = void 0; + this.reloadEditor(); return this.displayToc(); } displayToc() { - var toc; - toc = this.book.toc(); - console.log(toc); - return this.tree.set("data", toc); + this.book.toc(); + return this.tree.set("data", this.book); } }; @@ -225,237 +280,152 @@ BookletEntry = class BookletEntry { constructor() { - this.markAsDirty(); + this.name = "Untitled"; } save() {} remove() {} - markAsDirty() { - return this.dirty = true; - } - - markAsClean() { - return this.dirty = false; - } - toc() {} - titleFromFile(file) { - var content, title; - content = file.cache; - title = (new RegExp("^#+(.*)\n", "g")).exec(content); - if (!(title && title.length === 2)) { - return "Untitled"; + updateName() { + var t; + if (!this.descFile.dirty) { + return this.name; } - return title[1].trim(); + t = (new RegExp("^\s*#+(.*)[\n,$]", "g")).exec(this.descFile.cache); + if (!(t && t.length === 2)) { + return this.name; + } + return this.name = t[1].trim(); } }; BookletFolder = class BookletFolder extends BookletEntry { - constructor() { + constructor(type, path1, hasMeta) { super(); + this.type = type; + this.path = path1; + this.hasMeta = hasMeta; + this.nodes = []; + if (this.hasMeta) { + this.metaFile = `${this.path}/meta.json`.asFileHandler(); + } + this.descFile = `${this.path}/${this.type}.md`.asFileHandler(); } - save(apif) {} + add(chap) { + chap.parent = this; + return this.nodes.push(chap); + } + + size() { + return this.nodes.length; + } + + mkdir() { + var me; + me = this; + console.log("making:" + me.path); + return new Promise(function(r, e) { + var dir; + dir = me.path.asFileHandler(); + return dir.meta(function(d) { + var bname; + if (!d.error) { + return r(); + } + bname = dir.basename; + dir = dir.parent().asFileHandler(); + return dir.mk(bname, function(result) { + if (result.error) { + e(__("Error when create directory: {0}", result.error)); + } + return r(); + }); + }); + }); + } + + mkdirs() { + var me; + me = this; + return new Promise(function(r, e) { + var i, j, len, list, ref, v; + list = []; + if (me.hasMeta) { + 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) { + var el; + if (l.length === 0) { + return r(); + } + el = (l.splice(0, 1))[0]; + return el.mkdirs().then(function() { + return fn(l); + }); + }; + return fn(list); + }); + }); + } + + save(handle) { + return this.mkdirs().then(function() { + return handle.notify(__("All directories are created")); + }).catch(function(msg) { + return handle.error(msg); + }); + } + + toc() { + var j, len, ref, v; + this.updateName(); + ref = this.nodes; + for (j = 0, len = ref.length; j < len; j++) { + v = ref[j]; + v.toc(); + } + return this; + } remove(apif) {} - rename(newname) {} - }; Book = class Book extends BookletFolder { constructor(path) { - super(); - this.path = path; - this.chapters = []; - this.metaFile = `${this.path}/meta.json`.asFileHandler(); - this.descFile = `${this.path}/book.md`.asFileHandler(); - } - - addChapter(chap) { - chap.book = this; - return this.chapters.push(chap); - } - - size() { - return this.chapters.length; - } - - save(handle) { - var i, len, me, ref, v; - ref = this.chapters; - for (i = 0, len = ref.length; i < len; i++) { - v = ref[i]; - v.save(handle); - } - me = this; - if (this.dirty) { - if (this.descFile.dirty) { - this.descFile.write("text/plain", function(r) { - if (r.error) { - return handle.error(__("Fail to save file {0}: {1}", me.descFile.path, r.error)); - } - }); - } - this.metaFile.cache = this.toc(); - this.metaFile.dirty = true; - return this.metaFile.write("object", function(r) { - return handle.error(__("Fail to write book meta: {0}", r.error)); - me.markAsClean; - return handle.notify(__("Book saved")); - }); - } - } - - toc() { - var v; - return { - target: this, - name: this.titleFromFile(this.descFile), - nodes: (function() { - var i, len, ref, results; - ref = this.chapters; - results = []; - for (i = 0, len = ref.length; i < len; i++) { - v = ref[i]; - results.push(v.toc()); - } - return results; - }).call(this), - type: 'book' - }; + super('book', path, true); } }; BookletChapter = class BookletChapter extends BookletFolder { constructor(book) { - super(); - this.book = book; - this.book.addChapter(this); - this.sections = []; - this.path = `${this.book.path}/${this.book.size()}`; - this.metaFile = `${this.path}/meta.json`.asFileHandler(); - this.descFile = `${this.path}/chapter.md`.asFileHandler(); - } - - addSection(sec) { - sec.chapter = this; - return this.sections.push(sec); - } - - size() { - return this.sections.length; - } - - toc() { - var v; - return { - target: this, - name: this.titleFromFile(this.descFile), - nodes: (function() { - var i, len, ref, results; - ref = this.sections; - results = []; - for (i = 0, len = ref.length; i < len; i++) { - v = ref[i]; - results.push(v.toc()); - } - return results; - }).call(this), - type: 'chapter' - }; - } - - save(handle) { - var i, len, me, ref, v; - ref = this.sections; - for (i = 0, len = ref.length; i < len; i++) { - v = ref[i]; - v.save(handle); - } - me = this; - if (this.dirty) { - if (this.descFile.dirty) { - this.descFile.write("text/plain", function(r) { - if (r.error) { - return handle.error(__("Fail to save file {0}: {1}", me.descFile.path, r.error)); - } - }); - } - this.metaFile.cache = this.toc(); - this.metaFile.dirty = true; - return this.metaFile.write("object", function(r) { - return handle.error(__("Fail to write book meta: {0}", r.error)); - me.markAsClean; - return handle.notify(__("chapter saved")); - }); - } + var path; + path = `${book.path}/c_${book.size()}`; + super('chapter', path, true); + book.add(this); } }; BookletSection = class BookletSection extends BookletFolder { constructor(chapter) { - super(); - this.chapter = chapter; - this.chapter.addSection(this); - this.path = `${this.chapter.path}/${this.chapter.size()}`; - this.files = []; - this.descFile = `${this.path}/section.md`.asFileHandler(); - } - - addFile(file) { - file.section = this; - return this.files.push(file); - } - - toc() { - var v; - return { - target: this, - name: this.titleFromFile(this.descFile), - nodes: (function() { - var i, len, ref, results; - ref = this.files; - results = []; - for (i = 0, len = ref.length; i < len; i++) { - v = ref[i]; - results.push(v.toc()); - } - return results; - }).call(this), - type: 'section' - }; - } - - save() { - var i, len, me, ref, v; - ref = this.sections; - for (i = 0, len = ref.length; i < len; i++) { - v = ref[i]; - v.save(handle); - } - me = this; - if (this.dirty) { - 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)); - } - me.markAsClean; - return handle.notify(__("section saved")); - }); - } - } - } - - size() { - return this.files.length; + var path; + path = `${chapter.path}/s_${chapter.size()}`; + super("section", path, false); + chapter.add(this); } }; @@ -464,42 +434,33 @@ constructor(section) { super(); this.section = section; - this.section.addFile(this); - this.path = `${this.section.path}/${this.section.size()}.md`; + this.section.add(this); + this.path = `${this.section.path}/f_${this.section.size()}.md`; this.descFile = this.path.asFileHandler(); } - getTitle() { - return console.log("hello"); - } - save(handle) { - var i, len, me, ref, v; + var j, len, me, ref, v; ref = this.sections; - for (i = 0, len = ref.length; i < len; i++) { - v = ref[i]; + for (j = 0, len = ref.length; j < len; j++) { + v = ref[j]; v.save(this.descFile); } me = this; - if (this.dirty) { - 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)); - } - me.markAsClean; - return handle.notify(__("Book saved")); - }); - } + 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)); + } + this.descFile.dirty = false; + return handle.notify(__("Book saved")); + }); } } toc() { - return { - target: this, - name: this.titleFromFile(this.handle), - type: 'file' - }; + this.updateName(); + return this; } }; diff --git a/Booklet/coffees/common.coffee b/Booklet/coffees/common.coffee index 708355b..8d1a2d2 100644 --- a/Booklet/coffees/common.coffee +++ b/Booklet/coffees/common.coffee @@ -1,161 +1,112 @@ class BookletEntry constructor: () -> - @markAsDirty() + @name = "Untitled" + save: () -> remove: () -> - - markAsDirty: () -> @dirty = true - markAsClean: () -> @dirty = false toc: () -> + - titleFromFile:(file) -> - content = file.cache - title = (new RegExp "^#+(.*)\n", "g").exec content - return "Untitled" unless title and title.length is 2 - return title[1].trim() + updateName:() -> + return @name unless @descFile.dirty + t = (new RegExp "^\s*#+(.*)[\n,$]", "g").exec @descFile.cache + return @name unless t and t.length is 2 + @name = t[1].trim() + class BookletFolder extends BookletEntry - constructor: () -> + constructor: (@type, @path, @hasMeta) -> super() + @nodes = [] + @metaFile = "#{@path}/meta.json".asFileHandler() if @hasMeta + @descFile = "#{@path}/#{@type}.md".asFileHandler() - save: (apif) -> + add: (chap) -> + chap.parent = @ + @nodes.push chap + + size: () -> + return @nodes.length + + mkdir: () -> + me = @ + console.log "making:" + me.path + return new Promise (r, e) -> + dir = me.path.asFileHandler() + dir.meta (d) -> + return r() unless d.error + bname = dir.basename + dir = dir.parent().asFileHandler() + dir.mk bname, (result) -> + e __("Error when create directory: {0}", result.error) if result.error + r() + + mkdirs: () -> + me = @ + return new Promise (r, e) -> + list = [] + list[i] = v for v, i in me.nodes if me.hasMeta + console.log list + me.mkdir().then () -> + fn = (l) -> + return r() if l.length is 0 + el = (l.splice 0, 1)[0] + el.mkdirs().then () -> + fn l + return fn list + + + save:(handle) -> + @mkdirs().then ()-> + handle.notify __("All directories are created") + .catch (msg) -> + handle.error msg + + toc: () -> + @updateName() + v.toc() for v in @nodes + @ remove: (apif) -> - rename: (newname) -> - class Book extends BookletFolder - constructor: (@path) -> - super() - @chapters = [] - @metaFile = "#{@path}/meta.json".asFileHandler() - @descFile = "#{@path}/book.md".asFileHandler() + constructor: (path) -> + super 'book', path, true - addChapter: (chap) -> - chap.book = @ - @chapters.push chap - - size: () -> - return @chapters.length - save:(handle) -> - v.save handle for v in @chapters - me = @ - if @dirty - if @descFile.dirty - @descFile.write "text/plain", (r) -> - handle.error __("Fail to save file {0}: {1}", me.descFile.path, r.error) if r.error - @metaFile.cache = @toc() - @metaFile.dirty = true - @metaFile.write "object", (r) -> - return handle.error __("Fail to write book meta: {0}", r.error) - me.markAsClean - handle.notify __("Book saved") - - toc: () -> - return { - target: @, - name: @titleFromFile(@descFile), - nodes: v.toc() for v in @chapters, - type: 'book' - } class BookletChapter extends BookletFolder - constructor: (@book) -> - super() - @book.addChapter @ - @sections = [] - @path = "#{@book.path}/#{@book.size()}" - @metaFile = "#{@path}/meta.json".asFileHandler() - @descFile = "#{@path}/chapter.md".asFileHandler() - - addSection: (sec) -> - sec.chapter = @ - @sections.push sec - - size: () -> - return @sections.length - - toc: () -> - return { - target: @, - name: @titleFromFile(@descFile), - nodes: v.toc() for v in @sections, - type: 'chapter' - } - - save:(handle) -> - v.save handle for v in @sections - me = @ - if @dirty - if @descFile.dirty - @descFile.write "text/plain", (r) -> - handle.error __("Fail to save file {0}: {1}", me.descFile.path, r.error) if r.error - @metaFile.cache = @toc() - @metaFile.dirty = true - @metaFile.write "object", (r) -> - return handle.error __("Fail to write book meta: {0}", r.error) - me.markAsClean - handle.notify __("chapter saved") + constructor: (book) -> + path = "#{book.path}/c_#{book.size()}" + super 'chapter', path, true + book.add @ class BookletSection extends BookletFolder - constructor: (@chapter) -> - super() - @chapter.addSection @ - @path = "#{@chapter.path}/#{@chapter.size()}" - @files = [] - @descFile = "#{@path}/section.md".asFileHandler() - - addFile: (file) -> - file.section = @ - @files.push file - - toc: () -> - return { - target: @, - name: @titleFromFile(@descFile), - nodes: v.toc() for v in @files, - type: 'section' - } - - save: () -> - v.save handle for v in @sections - me = @ - if @dirty - if @descFile.dirty - @descFile.write "text/plain", (r) -> - handle.error __("Fail to save file {0}: {1}", me.descFile.path, r.error) if r.error - me.markAsClean - handle.notify __("section saved") - - size: () -> - return @files.length + constructor: (chapter) -> + path = "#{chapter.path}/s_#{chapter.size()}" + super "section", path, false + chapter.add @ + class BookletFile extends BookletEntry constructor: (@section) -> super() - @section.addFile @ - @path = "#{@section.path}/#{@section.size()}.md" + @section.add @ + @path = "#{@section.path}/f_#{@section.size()}.md" @descFile = @path.asFileHandler() - getTitle: () -> - console.log "hello" save: (handle) -> v.save @descFile for v in @sections me = @ - if @dirty - if @descFile.dirty - @descFile.write "text/plain", (r) -> - handle.error __("Fail to save file {0}: {1}", me.descFile.path, r.error) if r.error - me.markAsClean - handle.notify __("Book saved") + 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") toc: () -> - return { - target: @, - name: @titleFromFile(@handle), - type: 'file' - } \ No newline at end of file + @updateName() + @ \ No newline at end of file diff --git a/Booklet/coffees/main.coffee b/Booklet/coffees/main.coffee index d4549f2..ea041fc 100644 --- a/Booklet/coffees/main.coffee +++ b/Booklet/coffees/main.coffee @@ -6,11 +6,10 @@ class Booklet extends this.OS.GUI.BaseApplication me = @ @tree = @find "toc-ui" @currentToc = undefined - @tree.set "ontreeselect", (e) -> - me.saveContext() - me.currfile = e.target.descFile - me.reloadEditor() - me.currentToc = e + @on "treeselect", (e) -> + return if (me.currentToc is e) or (e is undefined) or (e.treepath is 0) + me.open e + @initEditor() @resizeContent() @tree.contextmenuHandler = (e, m) -> @@ -20,10 +19,25 @@ class Booklet extends this.OS.GUI.BaseApplication m.set "onmenuselect", (evt) -> me[evt.item.data.dataid]() m.show e + @editor.codemirror.on "change", () -> + return unless me.currentToc + me.currentToc.descFile.dirty = true newChapter: () -> - console.log @currentToc + return @error __("No book selected") unless @currentToc and @currentToc.type is "book" + ch = new BookletChapter(@book) + @displayToc() + newSection: () -> + return @error __("No chapter selected") unless @currentToc and @currentToc.type is "chapter" + sec = new BookletSection(@currentToc) + @displayToc() + + newFile: () -> + return @error __("No section selected") unless @currentToc and @currentToc.type is "section" + file = new BookletFile(@currentToc) + @displayToc() + contextMenu: () -> return undefined unless @currentToc switch @currentToc.type @@ -48,7 +62,6 @@ class Booklet extends this.OS.GUI.BaseApplication markarea = @find "markarea" @container = @find "mycontainer" @previewOn = false - @currfile = "Untitled".asFileHandler() @editormux = false me = @ @editor = new SimpleMDE @@ -82,13 +95,18 @@ class Booklet extends this.OS.GUI.BaseApplication @on "hboxchange", (e) -> me.resizeContent() @bindKey "ALT-N", () -> me.actionFile "#{me.name}-New" @bindKey "ALT-O", () -> me.actionFile "#{me.name}-Open" + @bindKey "CTRL-S", () -> me.actionFile "#{me.name}-Save" reloadEditor: () -> - @editor.value @currfile.cache - @scheme.set "apptitle", "Booklet - #{@currfile.basename}" + if @currentToc is undefined + @editor.value "" + return @scheme.set "apptitle", @name + @editor.value @currentToc.descFile.cache || "" + @scheme.set "apptitle", "Booklet - #{@currentToc.descFile.path}" saveContext: () -> - @currfile.cache = @editor.value() + return unless @currentToc + @currentToc.descFile.cache = @editor.value() resizeContent: () -> children = ($ @container).children() @@ -106,6 +124,7 @@ class Booklet extends this.OS.GUI.BaseApplication child: [ { text: "__(New booklet)", dataid: "#{@name}-New", shortcut: "A-N" }, { text: "__(Open a booklet)", dataid: "#{@name}-Open", shortcut: "A-O" } + { text: "__(Save a booklet)", dataid: "#{@name}-Save", shortcut: "C-S" } ], onmenuselect: (e) -> me.actionFile e.item.data.dataid }] @@ -116,24 +135,32 @@ class Booklet extends this.OS.GUI.BaseApplication switch e when "#{@name}-Open" @openDialog "FileDiaLog", ( d, f ) -> - me.open "#{d}/#{f}".asFileHandler() + console.log "#{d}/#{f}".asFileHandler() , __("Open file"), { mimes: me.meta().mimes } when "#{@name}-New" @openDialog "FileDiaLog", ( d, f ) -> - me.newAt d - , __("Open file"), { mimes: ['dir'] } + me.newAt "#{d}/#{f}" + , __("Open file"), { mimes: ['dir'], file: { basename: __("BookName") }} + when "#{@name}-Save" + me.book.save(me) - open: (file) -> - + open: (toc) -> + @saveContext() + @currentToc = toc + @reloadEditor() + @displayToc() newAt: (folder) -> + @tree.set "selectedItem", false @book = new Book(folder) + @book.treepath = @book.path + @currentToc = undefined + @reloadEditor() @displayToc() displayToc: () -> - toc = @book.toc() - console.log toc - @tree.set "data", toc + @book.toc() + @tree.set "data", @book Booklet.dependencies = [ "mde/simplemde.min" ]