From 58d0b5d16fb56c6a6af24b67710e93d9e74ae0ed Mon Sep 17 00:00:00 2001 From: Xuan Sang LE Date: Sun, 18 Feb 2018 21:11:49 +0100 Subject: [PATCH] alpha version of Blogger --- src/core/BaseDialog.coffee | 10 ++- src/core/api.coffee | 40 ++++++++++ src/core/vfs.coffee | 12 --- src/packages/Blogger/main.coffee | 126 ++++++++++++++++++++++++++++++- src/packages/Blogger/main.css | 17 ++++- src/packages/Blogger/scheme.html | 10 ++- 6 files changed, 196 insertions(+), 19 deletions(-) diff --git a/src/core/BaseDialog.coffee b/src/core/BaseDialog.coffee index eab9ec7..7879813 100644 --- a/src/core/BaseDialog.coffee +++ b/src/core/BaseDialog.coffee @@ -285,7 +285,15 @@ class FileDiaLog extends BaseDialog ($ filename).val f.filename if f.type is "file" (@find "bt-ok").set "onbtclick", (e) -> f = fileview.get "selectedFile" - return unless f + return me.notify "Please select a file" unless f + if me.data and me.data.mimes + #verify the mime + m = false + for v in me.data.mimes + if f.mime.match (new RegExp v, "g") + m = true + break + return me.notify "Only #{me.data.mimes.join(",")} could be selected" unless m d = f.path d = f.path.asFileHandler().parent() if f.type is "file" me.handler d, ($ filename).val() if me.handler diff --git a/src/core/api.coffee b/src/core/api.coffee index 0a96dfc..3df26ae 100644 --- a/src/core/api.coffee +++ b/src/core/api.coffee @@ -1,3 +1,43 @@ +String.prototype.hash = () -> + hash = 5381 + i = this.length + hash = (hash * 33) ^ this.charCodeAt(--i) while i + hash >>> 0 + +String.prototype.asBase64 = () -> + tmp = encodeURIComponent this + return btoa ( tmp.replace /%([0-9A-F]{2})/g, (match, p1) -> + return String.fromCharCode (parseInt p1, 16) + ) +String.prototype.unescape = () -> + d = @ + d = d.replace /\\\\/g, "\\" + d = d.replace /\\"/g, '"' + d = d.replace /\\n/g, "\n" + d = d.replace /\\t/g, "\t" + d = d.replace /\\b/g, "\b" + d = d.replace /\\f/g, "\f" + d = d.replace /\\r/g, "\r" + d + +Date.prototype.toString = () -> + dd = @getDate() + mm = @getMonth() + 1 + yyyy = @getFullYear() + hh = @getHours() + mi = @getMinutes() + se = @getSeconds() + + dd = "0#{dd}" if dd < 10 + mm = "0#{mm}" if mm < 10 + hh = "0#{hh}" if hh < 10 + mi = "0#{mi}" if mi < 10 + se = "0#{se}" if se < 10 + return "#{dd}/#{mm}/#{yyyy} #{hh}:#{mi}:#{se}" + +Date.prototype.timestamp = () -> + return @getTime() / 1000 | 0 + self.OS.API = # the handler object could be a any remote or local handle to # fetch user data, used by the API to make requests diff --git a/src/core/vfs.coffee b/src/core/vfs.coffee index 8371ea0..1006608 100644 --- a/src/core/vfs.coffee +++ b/src/core/vfs.coffee @@ -1,15 +1,3 @@ -String.prototype.hash = () -> - hash = 5381 - i = this.length - hash = (hash * 33) ^ this.charCodeAt(--i) while i - hash >>> 0 - -String.prototype.asBase64 = () -> - tmp = encodeURIComponent this - return btoa ( tmp.replace /%([0-9A-F]{2})/g, (match, p1) -> - return String.fromCharCode (parseInt p1, 16) - ) - String.prototype.asFileHandler = () -> list = @split ":///" handlers = _API.VFS.findHandlers list[0] diff --git a/src/packages/Blogger/main.coffee b/src/packages/Blogger/main.coffee index 50617c7..be8fdab 100644 --- a/src/packages/Blogger/main.coffee +++ b/src/packages/Blogger/main.coffee @@ -14,10 +14,12 @@ class Blogger extends this.OS.GUI.BaseApplication @cvlist = @find "cv-list" @cvlist.set "ontreeselect", (d) -> me.CVSectionByCID Number(d.id) + @inputtags = @.find "input-tags" @bloglist = @find "blog-list" @userdb = new @_api.DB("user") @cvcatdb = new @_api.DB("cv_cat") @cvsecdb = new @_api.DB("cv_sections") + @blogdb = new @_api.DB("blogs") @tabbar.set "onlistselect", (e) -> ($ el).hide() for el in me.containers me.fetchData e.idx @@ -78,6 +80,7 @@ class Blogger extends this.OS.GUI.BaseApplication d.cid = Number cat.id d.start = Number d.start d.end = Number d.end + d.publish = 1 me.cvsecdb.save d, (r) -> return me.error "Cannot save section: #{r.error}" if r.error me.CVSectionByCID Number(cat.id) @@ -92,12 +95,63 @@ class Blogger extends this.OS.GUI.BaseApplication d.cid = Number sec.cid d.start = Number d.start d.end = Number d.end + d.publish = Number sec.publish me.cvsecdb.save d, (r) -> return me.error "Cannot save section: #{r.error}" if r.error console.log d.cid me.CVSectionByCID Number(sec.cid) , "Modify section entry", sec + + @editor = new SimpleMDE + element: me.find "markarea" + autofocus: true + tabSize: 4 + indentWithTabs: true + toolbar: [ + { + name: "new", + className: "fa fa-file", + action: (e) -> + me.bloglist.set "selected", -1 + me.editor.value "" + me.inputtags.value = "" + }, + { + name: "save", + className: "fa fa-save", + action: (e) -> + me.saveBlog() + } + , "|", "bold", "italic", "heading", "|", "quote", "code", + "unordered-list", "ordered-list", "|", "link", + "image", "table", "horizontal-rule", + { + name: "image", + className: "fa fa-file-image-o", + action: (e) -> + me.openDialog "FileDiaLog", (d, n) -> + doc = me.editor.codemirror.getDoc() + doc.replaceSelection "![](#{me._api.handler.get}/#{d}/#{n})" + , "Select image file", { mimes: ["image/.*"] } + }, + "|", + { + name: "preview", + className: "fa fa-eye no-disable", + action: (e) -> + me.previewOn = !me.previewOn + SimpleMDE.togglePreview e + } + ] + @bloglist.set "onlistselect", (e) -> + sel = me.bloglist.get "selected" + return unless sel + me.editor.value sel.content + me.inputtags.value = sel.tags + + @on "vboxchange", () -> + me.resizeContent() # USER TAB fetchData: (idx) -> me = @ @@ -112,7 +166,7 @@ class Blogger extends this.OS.GUI.BaseApplication when 1 # category @refreshCVCat() else - console.log "Not implemented yet" + @loadBlogs() saveUser:() -> me = @ @@ -152,7 +206,13 @@ class Blogger extends this.OS.GUI.BaseApplication CVSectionByCID: (cid) -> me = @ - @cvsecdb.find "cid=#{cid} ORDER BY start DESC", (d) -> + cond = + exp: + "=": + cid: cid + order: + start: "DESC" + @cvsecdb.find cond, (d) -> return me.notify "Section list is empty, please add one" if d.error v.text = v.title for v in d.result items = [] @@ -172,7 +232,7 @@ class Blogger extends this.OS.GUI.BaseApplication items.push v el = me.find "cv-sec-list" el.set "onitemclose", (e) -> - d = me.openDialog "YesNoDialog", (b) -> + me.openDialog "YesNoDialog", (b) -> return unless b me.cvsecdb.delete e.item.item.id, (r) -> return me.error "Cannot delete the section: #{r.error}" if r.error @@ -182,6 +242,66 @@ class Blogger extends this.OS.GUI.BaseApplication return false el.set "items", items + # blog + saveBlog: () -> + me = @ + sel = @bloglist.get "selected" + tags = @inputtags.value + content = @editor.value() + title = (new RegExp "^#+(.*)\n", "g").exec content + return @notify "Please insert a title in the text: beginning with heading" unless title and title.length is 2 + return @notify "Please enter tags" if tags is "" + d = new Date() + data = + content: content + title: title[1].trim() + tags: tags + ctime: if sel then sel.ctime else d.timestamp() + ctimestr: if sel then sel.ctimestr else d.toString() + utime: d.timestamp() + utimestr: d.toString() + + data.id = sel.id if sel + + #save the data + @blogdb.save data, (r) -> + return me.error "Cannot save blog: #{r.error}" if r.error + me.loadBlogs() + + # load blog + loadBlogs: () -> + me = @ + @blogdb.get null, (r) -> + for v in r.result + v.text = v.title + v.complex = true + v.closable = true + v.content = v.content.unescape() + v.detail = [ + { text: "Created: #{v.ctimestr}", class: "blog-dates" }, + { text: "Updated: #{v.utimestr}", class: "blog-dates" }] + me.bloglist.set "onitemclose", (e) -> + me.openDialog "YesNoDialog", (b) -> + return unless b + me.blogdb.delete e.item.item.id, (r) -> + return me.error "Cannot delete: #{r.error}" if r.error + me.bloglist.remove e.item.item, true + me.bloglist.set "selected", -1 + me.editor.value "" + me.inputtags.value = "" + , "Delete a post" , + { iconclass: "fa fa-question-circle", text: "Do you really want to delete this post ?" } + return false + me.bloglist.set "items", r.result + + resizeContent: () -> + container = @find "editor-container" + children = ($ container).children() + titlebar = (($ @scheme).find ".afx-window-top")[0] + toolbar = children[1] + statusbar = children[4] + cheight = ($ @scheme).height() - ($ titlebar).height() - ($ toolbar).height() - ($ statusbar).height() - 90 + ($ children[2]).css("height", cheight + "px") Blogger.singleton = true Blogger.dependencies = [ "mde/simplemde.min" ] this.OS.register "Blogger", Blogger \ No newline at end of file diff --git a/src/packages/Blogger/main.css b/src/packages/Blogger/main.css index b8c72b5..8fd3768 100644 --- a/src/packages/Blogger/main.css +++ b/src/packages/Blogger/main.css @@ -52,8 +52,11 @@ afx-app-window[data-id="blogger-win"] afx-list-view[ data-id = "cv-sec-list"] > font-weight: bold; } +afx-app-window[data-id="blogger-win"] afx-list-view[ data-id = "cv-sec-list"] > div.list-container > ul >li:nth-child(odd){ + background-color: white; +} afx-app-window[data-id="blogger-win"] afx-list-view[ data-id = "cv-sec-list"] > div.list-container > ul > li.selected { - border: 2px solid #cbcbcb; + border: 2px solid #116cd6; color: #414339; background-color: transparent; border-radius: 5px; @@ -71,4 +74,16 @@ afx-app-window[data-id="blogger-win"] afx-list-view[ data-id = "cv-sec-list"] .c afx-app-window[data-id="blogger-win"] afx-list-view[ data-id = "cv-sec-list"] i.closable::before{ content: "\f014"; font-size: 15px; +} + +afx-app-window[data-id="blogger-win"] afx-list-view[ data-id = "blog-list"] > div.list-container > ul afx-label{ + font-weight: bold; +} + +afx-app-window[data-id="blogger-win"] afx-list-view[ data-id = "blog-list"] > div.list-container > ul .blog-dates{ + font-size: 10px; +} + +afx-app-window[data-id="blogger-win"] afx-list-view[ data-id = "blog-list"] > div.list-container > ul > li.selected .blog-dates{ + color: white; } \ No newline at end of file diff --git a/src/packages/Blogger/scheme.html b/src/packages/Blogger/scheme.html index 8b45f04..3022c29 100644 --- a/src/packages/Blogger/scheme.html +++ b/src/packages/Blogger/scheme.html @@ -53,9 +53,15 @@ - + + - blog here +
+ +
+ + +