refactory code

This commit is contained in:
Xuan Sang LE 2020-05-24 11:52:22 +02:00
parent 0c93ff7c9c
commit f11509120e
3 changed files with 435 additions and 449 deletions

View File

@ -12,7 +12,6 @@ endif
coffees= src/core/core.coffee \
src/core/api.coffee \
src/core/settings.coffee \
src/core/handles/RemoteHandle.coffee \
src/core/Announcerment.coffee \

View File

@ -1,446 +0,0 @@
# Copyright 2017-2018 Xuan Sang LE <xsang.le AT gmail DOT com>
# AnTOS Web desktop is is licensed under the GNU General Public
# License v3.0, see the LICENCE file for more information
# This program is free software: you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation, either version 3 of
# the License, or (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
# You should have received a copy of the GNU General Public License
#along with this program. If not, see https://www.gnu.org/licenses/.
class FormatedString
constructor: (@fs, args) ->
@values = []
return unless args
@values[i] = args[i] for i in [0..args.length - 1]
toString: () ->
@__()
__: () ->
return @fs.l().replace /{(\d+)}/g, (match, number) =>
return if typeof @values[number] != 'undefined' then @values[number].__() else match
hash: () ->
@__().hash()
match: (t) ->
@__().match t
asBase64: () ->
@__().asBase64()
unescape: () ->
@__().unescape()
asUint8Array: () ->
@__().asUint8Array()
format: () ->
args = arguments
@values[i] = args[i] for i in [0..args.length - 1]
class Version
constructor:(@string) ->
arr = @string.split "-"
br =
"r": 3,
"b": 2,
"a": 1
@branch = 3
@branch = br[arr[1]] if arr.length is 2 and br[arr[1]]
mt = arr[0].match /\d+/g
throw new Error __("Version string is in invalid format: {0}", @string) if not mt
@major = 0
@minor = 0
@patch = 0
@major = Number mt[0] if mt.length >= 1
@minor = Number mt[1] if mt.length >= 2
@patch = Number mt[2] if mt.length >= 3
# this function return
# 0 if the version is unchanged
# 1 if the current version is newer
# -1 if the current version is older
compare: (o) ->
other = o.__v()
return 1 if @branch > other.branch
return -1 if @branch < other.branch
return 0 if @major is other.major and @minor is other.minor and @patch is other.patch
return 1 if @major > other.major
return -1 if @major < other.major
return 1 if @minor > other.minor
return -1 if @minor < other.minor
return 1 if @patch > other.patch
return -1
nt: (o) ->
return (@compare o) is 1
ot: (o) ->
return (@compare o) is -1
__v: () -> @
toString: () -> @string
Object.defineProperty Object.prototype, '__',
value: () ->
return @toString()
enumerable: false
writable: true
String.prototype.hash = () ->
hash = 5381
i = this.length
hash = (hash * 33) ^ this.charCodeAt(--i) while i
hash >>> 0
String.prototype.__v = () ->
return new Version @
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
String.prototype.asUint8Array = () ->
bytes = []
for i in [0..(@length - 1)]
bytes.push @charCodeAt i
bytes = new Uint8Array(bytes)
return bytes
if not String.prototype.format
String.prototype.format = () ->
args = arguments
return @replace /{(\d+)}/g, (match, number) ->
return if typeof args[number] != 'undefined' then args[number].__() else match
String.prototype.f = () ->
args = arguments
return new FormatedString(@, args)
String.prototype.__ = () ->
match = @match(/^__\((.*)\)$/)
return match[1].l() if match
return @
String.prototype.l = () ->
Ant.OS.API.lang[@] = @ unless Ant.OS.API.lang[@]
return Ant.OS.API.lang[@]
# language directive
this.__ = () ->
args = arguments
return "Undefined" unless args.length > 0
d = args[0]
d.l()
return new FormatedString d, (args[i] for i in [1 .. args.length - 1])
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
# chaning error
Ant.__e = (e) ->
reason = new Error(e.toString())
reason.stack += "\nCaused By:\n" + e.stack
return reason
Ant.OS.API =
# the handle object could be a any remote or local handle to
# fetch user data, used by the API to make requests
# handles are defined in /src/handles
handle: {}
shared: {} # shared libraries
searchHandle: {}
lang: {}
#request a user data
mid: () ->
return Ant.OS.announcer.getMID()
post: (p, d) ->
new Promise (resolve, reject) ->
q = Ant.OS.announcer.getMID()
Ant.OS.API.loading q, p
$.ajax {
type: 'POST',
url: p,
contentType: 'application/json',
data: JSON.stringify(d,
(k, v) ->
return undefined if k is "domel"
return v
, 4),
dataType: 'json',
success: null
}
.done (data) ->
Ant.OS.API.loaded q, p, "OK"
resolve(data)
.fail (j, s, e) ->
Ant.OS.API.loaded q, p, "FAIL"
if e
reject __e e
else
reject(Ant.OS.API.throwe s)
blob: (p) ->
new Promise (resolve, reject) ->
q = Ant.OS.announcer.getMID()
r = new XMLHttpRequest()
r.open "GET", p, true
r.responseType = "arraybuffer"
r.onload = (e) ->
if @status is 200 and @readyState is 4
Ant.OS.API.loaded q, p, "OK"
resolve @response
else
Ant.OS.API.loaded q, p, "FAIL"
reject Ant.OS.API.throwe __("Unable to get blob: {0}", p)
Ant.OS.API.loading q, p
r.send()
upload: (p, d) ->
new Promise (resolve, reject) ->
q = Ant.OS.announcer.getMID()
#insert a temporal file selector
o = ($ '<input>').attr('type', 'file').css("display", "none")
o.change () ->
Ant.OS.API.loading q, p
formd = new FormData()
formd.append 'path', d
# TODO: only one file is selected at this time
formd.append 'upload', o[0].files[0]
$.ajax {
url: p,
data: formd,
type: 'POST',
contentType: false,
processData: false,
}
.done (data) ->
Ant.OS.API.loaded q, p, "OK"
resolve(data)
o.remove()
.fail (j, s, e) ->
Ant.OS.API.loaded q, p, "FAIL"
if e
reject __e e
else
reject(Ant.OS.API.throwe s)
o.remove()
o.click()
saveblob: (name, b) ->
url = window.URL.createObjectURL b
o = ($ '<a>')
.attr("href", url)
.attr("download", name)
.css("display", "none")
.appendTo("body")
o[0].click()
window.URL.revokeObjectURL(url)
o.remove()
loading: (q, p) ->
Ant.OS.announcer.trigger "loading", { id: q, data: { m: "#{p}", s: true }, name: "OS" }
loaded: (q, p, m ) ->
Ant.OS.announcer.trigger "loaded", {
id: q, data: { m: "#{m}: #{p}", s: false }, name: "OS" }
get: (p, t) ->
new Promise (resolve, reject) ->
conf =
type: 'GET',
url: p
conf.dataType = t if t
q = Ant.OS.announcer.getMID()
Ant.OS.API.loading q, p
$.ajax conf
.done (data) ->
Ant.OS.API.loaded q, p, "OK"
resolve(data)
.fail (j, s, e) ->
Ant.OS.API.loaded q, p, "FAIL"
if e
reject __e e
else
reject(Ant.OS.API.throwe s)
script: (p) ->
Ant.OS.API.get p, "script"
resource: (r) ->
path = "resources/#{r}"
Ant.OS.API.get path
libready: (l) ->
return Ant.OS.API.shared[l] || false
requires: (l) ->
new Promise (resolve, reject) ->
if not Ant.OS.API.shared[l]
libfp = l.asFileHandle()
switch libfp.ext
when "css"
libfp.onready()
.then () ->
$('<link>', {
rel: 'stylesheet',
type: 'text/css',
'href': "#{libfp.getlink()}"
})
.appendTo 'head'
Ant.OS.API.shared[l] = true
console.log "Loaded :", l
Ant.OS.announcer.trigger "sharedlibraryloaded", l
resolve undefined
.catch (e) -> reject __e e
when "js"
Ant.OS.API.script libfp.getlink()
.then (data) ->
Ant.OS.API.shared[l] = true
console.log "Loaded :", l
Ant.OS.announcer.trigger "sharedlibraryloaded", l
resolve(data)
.catch (e) ->
reject __e e
else
reject Ant.OS.API.throwe __("Invalid library: {0}", l)
else
console.log l, "Library exist, no need to load"
Ant.OS.announcer.trigger "sharedlibraryloaded", l
resolve()
require: (libs) ->
new Promise (resolve, reject) ->
return resolve() unless libs.length > 0
Ant.OS.announcer.observable.one "sharedlibraryloaded", (l) ->
libs.splice 0, 1
Ant.OS.API.require libs
.catch (e) -> reject __e e
.then (r) -> resolve(r)
Ant.OS.API.requires libs[0]
.catch (e) -> reject __e e
packages:
fetch: () ->
Ant.OS.API.handle.packages {
command: "list", args: { paths: (v for k, v of Ant.OS.setting.system.pkgpaths) }
}
cache: () ->
Ant.OS.API.handle.packages {
command: "cache", args: { paths: (v for k, v of Ant.OS.setting.system.pkgpaths) }
}
setting: (f) ->
Ant.OS.API.handle.setting f
apigateway: (d, ws) ->
return Ant.OS.API.handle.apigateway d, ws
search: (text) ->
r = []
for k, v of Ant.OS.API.searchHandle
ret = Ant.OS.API.searchHandle[k](text)
if ret.length > 0
ret.unshift { text: k, class: "search-header", dataid: "header" }
r = r.concat ret
return r
onsearch: (name, fn) ->
Ant.OS.API.searchHandle[name] = fn unless Ant.OS.API.searchHandle[name]
setLocale: (name) ->
new Promise (resolve, reject) ->
path = "resources/languages/#{name}.json"
Ant.OS.API.get(path, "json")
.then (d) ->
Ant.OS.setting.system.locale = name
Ant.OS.API.lang = d
Ant.OS.announcer.trigger "systemlocalechange", name
resolve d
.catch (e) ->
reject __e e
throwe: (n) ->
err = undefined
try
throw new Error(n)
catch e
err = e
return "" if not err
return err
setClipboard: (v) ->
$el = $("#clipboard")
$el.val v
$el[0].select()
$el[0].setSelectionRange(0, 99999)
document.execCommand("copy")
getClipboard: () ->
new Promise (resolve, reject) ->
$el = $("#clipboard")
return resolve $el.val() unless navigator.clipboard
navigator.clipboard.readText().then (d) ->
resolve d
.catch (e) -> reject __e e
# utilities functioncs
switcher: () ->
o = {}
p = {}
p[arguments[i]] = false for i in [0..arguments.length - 1 ]
Object.defineProperty o, "__p", {
enumerable: false,
value: p
}
fn = (o, v) ->
Object.defineProperty o, v, {
enumerable: true,
set: (value) ->
for k, l of @__p
@__p[k] = false
o.__p[v] = value
, get: () ->
return o.__p[v]
}
for k, v of o.__p
fn o, k
Object.defineProperty o, "selected", {
configurable: true,
enumerable: false,
get: () ->
for k, v of o.__p
return k if v
}
return o

View File

@ -17,8 +17,164 @@
#along with this program. If not, see https://www.gnu.org/licenses/.
'use strict'
#define the OS object
Ant = this
class FormatedString
constructor: (@fs, args) ->
@values = []
return unless args
@values[i] = args[i] for i in [0..args.length - 1]
toString: () ->
@__()
__: () ->
return @fs.l().replace /{(\d+)}/g, (match, number) =>
return if typeof @values[number] != 'undefined' then @values[number].__() else match
hash: () ->
@__().hash()
match: (t) ->
@__().match t
asBase64: () ->
@__().asBase64()
unescape: () ->
@__().unescape()
asUint8Array: () ->
@__().asUint8Array()
format: () ->
args = arguments
@values[i] = args[i] for i in [0..args.length - 1]
class Version
constructor:(@string) ->
arr = @string.split "-"
br =
"r": 3,
"b": 2,
"a": 1
@branch = 3
@branch = br[arr[1]] if arr.length is 2 and br[arr[1]]
mt = arr[0].match /\d+/g
throw new Error __("Version string is in invalid format: {0}", @string) if not mt
@major = 0
@minor = 0
@patch = 0
@major = Number mt[0] if mt.length >= 1
@minor = Number mt[1] if mt.length >= 2
@patch = Number mt[2] if mt.length >= 3
# this function return
# 0 if the version is unchanged
# 1 if the current version is newer
# -1 if the current version is older
compare: (o) ->
other = o.__v()
return 1 if @branch > other.branch
return -1 if @branch < other.branch
return 0 if @major is other.major and @minor is other.minor and @patch is other.patch
return 1 if @major > other.major
return -1 if @major < other.major
return 1 if @minor > other.minor
return -1 if @minor < other.minor
return 1 if @patch > other.patch
return -1
nt: (o) ->
return (@compare o) is 1
ot: (o) ->
return (@compare o) is -1
__v: () -> @
toString: () -> @string
Object.defineProperty Object.prototype, '__',
value: () ->
return @toString()
enumerable: false
writable: true
String.prototype.hash = () ->
hash = 5381
i = this.length
hash = (hash * 33) ^ this.charCodeAt(--i) while i
hash >>> 0
String.prototype.__v = () ->
return new Version @
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
String.prototype.asUint8Array = () ->
bytes = []
for i in [0..(@length - 1)]
bytes.push @charCodeAt i
bytes = new Uint8Array(bytes)
return bytes
if not String.prototype.format
String.prototype.format = () ->
args = arguments
return @replace /{(\d+)}/g, (match, number) ->
return if typeof args[number] != 'undefined' then args[number].__() else match
String.prototype.f = () ->
args = arguments
return new FormatedString(@, args)
String.prototype.__ = () ->
match = @match(/^__\((.*)\)$/)
return match[1].l() if match
return @
String.prototype.l = () ->
Ant.OS.API.lang[@] = @ unless Ant.OS.API.lang[@]
return Ant.OS.API.lang[@]
# language directive
this.__ = () ->
args = arguments
return "Undefined" unless args.length > 0
d = args[0]
d.l()
return new FormatedString d, (args[i] for i in [1 .. args.length - 1])
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
# chaning error
this.__e = (e) ->
reason = new Error(e.toString())
reason.stack += "\nCaused By:\n" + e.stack
return reason
#define the OS object
Ant.OS or=
API: {}
@ -141,4 +297,281 @@ Ant.OS or=
console.error e
onexit: (n, f) ->
Ant.OS.cleanupHandles[n] = f unless Ant.OS.cleanupHandles[n]
Ant.OS.cleanupHandles[n] = f unless Ant.OS.cleanupHandles[n]
Ant.OS.API =
# the handle object could be a any remote or local handle to
# fetch user data, used by the API to make requests
# handles are defined in /src/handles
handle: {}
shared: {} # shared libraries
searchHandle: {}
lang: {}
#request a user data
mid: () ->
return Ant.OS.announcer.getMID()
post: (p, d) ->
new Promise (resolve, reject) ->
q = Ant.OS.announcer.getMID()
Ant.OS.API.loading q, p
$.ajax {
type: 'POST',
url: p,
contentType: 'application/json',
data: JSON.stringify(d,
(k, v) ->
return undefined if k is "domel"
return v
, 4),
dataType: 'json',
success: null
}
.done (data) ->
Ant.OS.API.loaded q, p, "OK"
resolve(data)
.fail (j, s, e) ->
Ant.OS.API.loaded q, p, "FAIL"
if e
reject __e e
else
reject(Ant.OS.API.throwe s)
blob: (p) ->
new Promise (resolve, reject) ->
q = Ant.OS.announcer.getMID()
r = new XMLHttpRequest()
r.open "GET", p, true
r.responseType = "arraybuffer"
r.onload = (e) ->
if @status is 200 and @readyState is 4
Ant.OS.API.loaded q, p, "OK"
resolve @response
else
Ant.OS.API.loaded q, p, "FAIL"
reject Ant.OS.API.throwe __("Unable to get blob: {0}", p)
Ant.OS.API.loading q, p
r.send()
upload: (p, d) ->
new Promise (resolve, reject) ->
q = Ant.OS.announcer.getMID()
#insert a temporal file selector
o = ($ '<input>').attr('type', 'file').css("display", "none")
o.change () ->
Ant.OS.API.loading q, p
formd = new FormData()
formd.append 'path', d
# TODO: only one file is selected at this time
formd.append 'upload', o[0].files[0]
$.ajax {
url: p,
data: formd,
type: 'POST',
contentType: false,
processData: false,
}
.done (data) ->
Ant.OS.API.loaded q, p, "OK"
resolve(data)
o.remove()
.fail (j, s, e) ->
Ant.OS.API.loaded q, p, "FAIL"
if e
reject __e e
else
reject(Ant.OS.API.throwe s)
o.remove()
o.click()
saveblob: (name, b) ->
url = window.URL.createObjectURL b
o = ($ '<a>')
.attr("href", url)
.attr("download", name)
.css("display", "none")
.appendTo("body")
o[0].click()
window.URL.revokeObjectURL(url)
o.remove()
loading: (q, p) ->
Ant.OS.announcer.trigger "loading", { id: q, data: { m: "#{p}", s: true }, name: "OS" }
loaded: (q, p, m ) ->
Ant.OS.announcer.trigger "loaded", {
id: q, data: { m: "#{m}: #{p}", s: false }, name: "OS" }
get: (p, t) ->
new Promise (resolve, reject) ->
conf =
type: 'GET',
url: p
conf.dataType = t if t
q = Ant.OS.announcer.getMID()
Ant.OS.API.loading q, p
$.ajax conf
.done (data) ->
Ant.OS.API.loaded q, p, "OK"
resolve(data)
.fail (j, s, e) ->
Ant.OS.API.loaded q, p, "FAIL"
if e
reject __e e
else
reject(Ant.OS.API.throwe s)
script: (p) ->
Ant.OS.API.get p, "script"
resource: (r) ->
path = "resources/#{r}"
Ant.OS.API.get path
libready: (l) ->
return Ant.OS.API.shared[l] || false
requires: (l) ->
new Promise (resolve, reject) ->
if not Ant.OS.API.shared[l]
libfp = l.asFileHandle()
switch libfp.ext
when "css"
libfp.onready()
.then () ->
$('<link>', {
rel: 'stylesheet',
type: 'text/css',
'href': "#{libfp.getlink()}"
})
.appendTo 'head'
Ant.OS.API.shared[l] = true
console.log "Loaded :", l
Ant.OS.announcer.trigger "sharedlibraryloaded", l
resolve undefined
.catch (e) -> reject __e e
when "js"
Ant.OS.API.script libfp.getlink()
.then (data) ->
Ant.OS.API.shared[l] = true
console.log "Loaded :", l
Ant.OS.announcer.trigger "sharedlibraryloaded", l
resolve(data)
.catch (e) ->
reject __e e
else
reject Ant.OS.API.throwe __("Invalid library: {0}", l)
else
console.log l, "Library exist, no need to load"
Ant.OS.announcer.trigger "sharedlibraryloaded", l
resolve()
require: (libs) ->
new Promise (resolve, reject) ->
return resolve() unless libs.length > 0
Ant.OS.announcer.observable.one "sharedlibraryloaded", (l) ->
libs.splice 0, 1
Ant.OS.API.require libs
.catch (e) -> reject __e e
.then (r) -> resolve(r)
Ant.OS.API.requires libs[0]
.catch (e) -> reject __e e
packages:
fetch: () ->
Ant.OS.API.handle.packages {
command: "list", args: { paths: (v for k, v of Ant.OS.setting.system.pkgpaths) }
}
cache: () ->
Ant.OS.API.handle.packages {
command: "cache", args: { paths: (v for k, v of Ant.OS.setting.system.pkgpaths) }
}
setting: (f) ->
Ant.OS.API.handle.setting f
apigateway: (d, ws) ->
return Ant.OS.API.handle.apigateway d, ws
search: (text) ->
r = []
for k, v of Ant.OS.API.searchHandle
ret = Ant.OS.API.searchHandle[k](text)
if ret.length > 0
ret.unshift { text: k, class: "search-header", dataid: "header" }
r = r.concat ret
return r
onsearch: (name, fn) ->
Ant.OS.API.searchHandle[name] = fn unless Ant.OS.API.searchHandle[name]
setLocale: (name) ->
new Promise (resolve, reject) ->
path = "resources/languages/#{name}.json"
Ant.OS.API.get(path, "json")
.then (d) ->
Ant.OS.setting.system.locale = name
Ant.OS.API.lang = d
Ant.OS.announcer.trigger "systemlocalechange", name
resolve d
.catch (e) ->
reject __e e
throwe: (n) ->
err = undefined
try
throw new Error(n)
catch e
err = e
return "" if not err
return err
setClipboard: (v) ->
$el = $("#clipboard")
$el.val v
$el[0].select()
$el[0].setSelectionRange(0, 99999)
document.execCommand("copy")
getClipboard: () ->
new Promise (resolve, reject) ->
$el = $("#clipboard")
return resolve $el.val() unless navigator.clipboard
navigator.clipboard.readText().then (d) ->
resolve d
.catch (e) -> reject __e e
# utilities functioncs
switcher: () ->
o = {}
p = {}
p[arguments[i]] = false for i in [0..arguments.length - 1 ]
Object.defineProperty o, "__p", {
enumerable: false,
value: p
}
fn = (o, v) ->
Object.defineProperty o, v, {
enumerable: true,
set: (value) ->
for k, l of @__p
@__p[k] = false
o.__p[v] = value
, get: () ->
return o.__p[v]
}
for k, v of o.__p
fn o, k
Object.defineProperty o, "selected", {
configurable: true,
enumerable: false,
get: () ->
for k, v of o.__p
return k if v
}
return o