2018-03-15 11:00:24 +01:00
|
|
|
# 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/.
|
2018-03-10 20:42:09 +01:00
|
|
|
class FormatedString
|
|
|
|
constructor: (@fs, args) ->
|
|
|
|
@values = []
|
|
|
|
return unless args
|
|
|
|
@values[i] = args[i] for i in [0..args.length - 1]
|
2018-03-10 22:46:28 +01:00
|
|
|
toString: () ->
|
|
|
|
@__()
|
2018-03-10 20:42:09 +01:00
|
|
|
__: () ->
|
|
|
|
me = @
|
2018-03-10 22:46:28 +01:00
|
|
|
return @fs.l().replace /{(\d+)}/g, (match, number) ->
|
2018-03-10 20:42:09 +01:00
|
|
|
return if typeof me.values[number] != 'undefined' then me.values[number] else match
|
|
|
|
hash: () ->
|
|
|
|
@__().hash()
|
|
|
|
|
|
|
|
asBase64: () ->
|
|
|
|
@__().asBase64()
|
|
|
|
|
|
|
|
unescape: () ->
|
|
|
|
@__().unescape()
|
|
|
|
|
|
|
|
asUint8Array: () ->
|
|
|
|
@__().asUint8Array()
|
|
|
|
|
|
|
|
format: () ->
|
|
|
|
args = arguments
|
|
|
|
@values[i] = args[i] for i in [0..args.length - 1]
|
2018-03-10 22:46:28 +01:00
|
|
|
|
|
|
|
Object.defineProperty Object.prototype, '__',
|
|
|
|
value: () ->
|
|
|
|
return @toString()
|
|
|
|
enumerable: false
|
|
|
|
writable: true
|
2018-03-10 20:42:09 +01:00
|
|
|
|
2018-02-18 21:11:49 +01:00
|
|
|
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
|
2018-03-10 20:42:09 +01:00
|
|
|
String.prototype.asUint8Array = () ->
|
2018-03-05 00:20:25 +01:00
|
|
|
bytes = []
|
|
|
|
for i in [0..(@length - 1)]
|
|
|
|
bytes.push @charCodeAt i
|
|
|
|
bytes = new Uint8Array(bytes)
|
|
|
|
return bytes
|
2018-02-18 21:11:49 +01:00
|
|
|
|
2018-03-09 19:54:33 +01:00
|
|
|
if not String.prototype.format
|
|
|
|
String.prototype.format = () ->
|
|
|
|
args = arguments
|
2018-03-10 23:24:53 +01:00
|
|
|
return @replace /{(\d+)}/g, (match, number) ->
|
|
|
|
return if typeof args[number] != 'undefined' then args[number] else match
|
2018-03-10 20:42:09 +01:00
|
|
|
|
|
|
|
String.prototype.f = () ->
|
|
|
|
args = arguments
|
|
|
|
return new FormatedString(@, args)
|
2018-03-10 12:22:01 +01:00
|
|
|
|
|
|
|
String.prototype.__ = () ->
|
|
|
|
match = @match(/^__\((.*)\)$/)
|
2018-03-10 22:46:28 +01:00
|
|
|
return match[1].l() if match
|
2018-03-10 12:22:01 +01:00
|
|
|
return @
|
2018-03-10 22:46:28 +01:00
|
|
|
String.prototype.l = () ->
|
|
|
|
_API = window.OS.API
|
|
|
|
_API.lang[@] = @ unless _API.lang[@]
|
|
|
|
return _API.lang[@]
|
2018-03-09 19:54:33 +01:00
|
|
|
# language directive
|
2018-03-10 20:42:09 +01:00
|
|
|
|
2018-03-09 19:54:33 +01:00
|
|
|
this.__ = () ->
|
|
|
|
_API = window.OS.API
|
|
|
|
args = arguments
|
|
|
|
return "Undefined" unless args.length > 0
|
|
|
|
d = args[0]
|
2018-03-10 22:46:28 +01:00
|
|
|
d.l()
|
|
|
|
return new FormatedString d, (args[i] for i in [1 .. args.length - 1])
|
2018-03-09 19:54:33 +01:00
|
|
|
|
2018-02-18 21:11:49 +01:00
|
|
|
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
|
|
|
|
|
2017-08-26 16:50:13 +02:00
|
|
|
self.OS.API =
|
2017-08-07 00:49:24 +02:00
|
|
|
# the handler object could be a any remote or local handle to
|
|
|
|
# fetch user data, used by the API to make requests
|
|
|
|
# handlers are defined in /src/handlers
|
2018-03-03 13:44:52 +01:00
|
|
|
handler: {}
|
2018-02-16 18:38:14 +01:00
|
|
|
shared: {} # shared libraries
|
2018-03-03 13:44:52 +01:00
|
|
|
searchHandler:{}
|
2018-03-09 19:54:33 +01:00
|
|
|
lang:{}
|
2017-08-07 00:49:24 +02:00
|
|
|
#request a user data
|
2018-03-01 13:56:42 +01:00
|
|
|
mid: () ->
|
|
|
|
return _courrier.getMID()
|
2017-08-26 16:50:13 +02:00
|
|
|
post: (p, d, c, f) ->
|
|
|
|
q = _courrier.getMID()
|
|
|
|
_API.loading q, p
|
2017-08-27 23:40:02 +02:00
|
|
|
|
2017-08-26 16:50:13 +02:00
|
|
|
$.ajax {
|
2017-08-27 23:40:02 +02:00
|
|
|
type: 'POST',
|
2017-08-26 16:50:13 +02:00
|
|
|
url: p,
|
2017-08-27 23:40:02 +02:00
|
|
|
contentType: 'application/json',
|
|
|
|
data: JSON.stringify d,
|
2018-01-29 19:16:29 +01:00
|
|
|
dataType: 'json',
|
2017-08-27 23:40:02 +02:00
|
|
|
success: null
|
2017-08-26 16:50:13 +02:00
|
|
|
}
|
2017-08-27 23:40:02 +02:00
|
|
|
#$.getJSON p, d
|
2017-08-26 16:50:13 +02:00
|
|
|
.done (data) ->
|
|
|
|
_API.loaded q, p, "OK"
|
|
|
|
c(data)
|
|
|
|
.fail (e, s) ->
|
|
|
|
_API.loaded q, p, "FAIL"
|
|
|
|
f(e, s)
|
2018-01-25 19:15:41 +01:00
|
|
|
|
|
|
|
blob: (p, c, f) ->
|
|
|
|
q = _courrier.getMID()
|
|
|
|
r = new XMLHttpRequest()
|
|
|
|
r.open "GET", p, true
|
|
|
|
r.responseType = "arraybuffer"
|
|
|
|
|
|
|
|
r.onload = (e) ->
|
|
|
|
if @status is 200 and @readyState is 4
|
|
|
|
c @response
|
|
|
|
_API.loaded q, p, "OK"
|
|
|
|
else
|
|
|
|
f e, @
|
|
|
|
_API.loaded q, p, "FAIL"
|
|
|
|
|
|
|
|
_API.loading q, p
|
|
|
|
r.send()
|
|
|
|
|
|
|
|
upload: (p, d, c, f) ->
|
|
|
|
q = _courrier.getMID()
|
|
|
|
#insert a temporal file selector
|
|
|
|
o = ($ '<input>').attr('type', 'file').css("display", "none")
|
|
|
|
o.change () ->
|
|
|
|
_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) ->
|
|
|
|
_API.loaded q, p, "OK"
|
|
|
|
c(data)
|
2018-02-28 15:33:57 +01:00
|
|
|
o.remove()
|
2018-01-25 19:15:41 +01:00
|
|
|
.fail (e, s) ->
|
|
|
|
_API.loaded q, p, "FAIL"
|
|
|
|
f(e, s)
|
2018-02-28 15:33:57 +01:00
|
|
|
o.remove()
|
2018-01-25 19:15:41 +01:00
|
|
|
|
|
|
|
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()
|
2017-08-07 00:49:24 +02:00
|
|
|
|
|
|
|
systemConfig: ->
|
|
|
|
_API.request 'config', (result) ->
|
|
|
|
console.log result
|
2017-08-26 16:50:13 +02:00
|
|
|
loading: (q, p) ->
|
|
|
|
_courrier.trigger "loading", { id: q, data: { m: "#{p}", s: true }, name: "OS" }
|
|
|
|
loaded: (q, p, m ) ->
|
|
|
|
_courrier.trigger "loaded", { id: q, data: { m: "#{m}: #{p}", s: false }, name: "OS" }
|
2018-01-29 19:16:29 +01:00
|
|
|
get: (p, c, f, t) ->
|
|
|
|
conf =
|
|
|
|
type: 'GET',
|
|
|
|
url: p,
|
|
|
|
conf.dataType = t if t
|
|
|
|
|
2017-08-26 16:50:13 +02:00
|
|
|
q = _courrier.getMID()
|
|
|
|
_API.loading q, p
|
2018-01-29 19:16:29 +01:00
|
|
|
$.ajax conf
|
2017-08-26 16:50:13 +02:00
|
|
|
.done (data) ->
|
|
|
|
_API.loaded q, p, "OK"
|
|
|
|
c(data)
|
|
|
|
.fail (e, s) ->
|
|
|
|
_API.loaded q, p, "FAIL"
|
|
|
|
f(e, s)
|
|
|
|
script: (p, c, f) ->
|
|
|
|
q = _courrier.getMID()
|
|
|
|
_API.loading q, p
|
|
|
|
$.getScript p
|
|
|
|
.done (data) ->
|
|
|
|
_API.loaded q, p, "OK"
|
|
|
|
c(data)
|
|
|
|
.fail (e, s) ->
|
|
|
|
_API.loaded q, p, "FAIL"
|
|
|
|
f(e, s)
|
2017-08-27 23:40:02 +02:00
|
|
|
resource: (r, c, f) ->
|
|
|
|
path = "resources/#{r}"
|
|
|
|
_API.get path, c, f
|
2018-01-29 19:16:29 +01:00
|
|
|
|
2018-02-27 16:40:36 +01:00
|
|
|
libready: (l) ->
|
|
|
|
return _API.shared[l] || false
|
|
|
|
|
2018-02-16 18:38:14 +01:00
|
|
|
require: (l,f) ->
|
|
|
|
if not _API.shared[l]
|
2018-02-27 16:40:36 +01:00
|
|
|
if l.match /^(https?:\/\/[^\s]+)/g
|
|
|
|
_API.script l, () ->
|
|
|
|
_API.shared[l] = true
|
|
|
|
_courrier.trigger "sharedlibraryloaded", l
|
|
|
|
f() if f
|
|
|
|
, (e, s) ->
|
2018-03-09 19:54:33 +01:00
|
|
|
_courrier.oserror __("Cannot load 3rd library at: {0}", l), e, r
|
2018-02-27 16:40:36 +01:00
|
|
|
else
|
2018-03-11 21:31:40 +01:00
|
|
|
path = "os://scripts/"
|
2018-02-27 16:40:36 +01:00
|
|
|
js = "#{path}#{l}.js"
|
|
|
|
js.asFileHandler().onready (d) ->
|
|
|
|
_API.shared[l] = true
|
|
|
|
el = $ '<script>', { src: "#{_API.handler.get}/#{js}" }
|
|
|
|
.appendTo 'head'
|
|
|
|
#load css file
|
|
|
|
css = "#{path}#{l}.css"
|
|
|
|
css.asFileHandler().onready (d) ->
|
|
|
|
el = $ '<link>', { rel: 'stylesheet', type: 'text/css', 'href': "#{_API.handler.get}/#{css}" }
|
|
|
|
.appendTo 'head'
|
|
|
|
, () ->
|
|
|
|
console.log "loaded", l
|
|
|
|
_courrier.trigger "sharedlibraryloaded", l
|
|
|
|
f() if f
|
2018-02-16 18:38:14 +01:00
|
|
|
else
|
2018-03-09 19:54:33 +01:00
|
|
|
console.log l, "Library exist, no need to load"
|
2018-02-16 18:38:14 +01:00
|
|
|
_courrier.trigger "sharedlibraryloaded", l
|
|
|
|
|
|
|
|
requires:(libs, f) ->
|
|
|
|
return f() unless libs.length > 0
|
|
|
|
_courrier.observable.one "sharedlibraryloaded", (l) ->
|
|
|
|
libs.splice 0, 1
|
|
|
|
_API.requires libs, f
|
|
|
|
_API.require libs[0], null
|
2018-01-29 19:16:29 +01:00
|
|
|
packages:
|
|
|
|
fetch: (f) ->
|
|
|
|
_API.handler.packages {
|
2018-03-05 00:20:25 +01:00
|
|
|
command: "list", args: { paths: (v for k, v of _OS.setting.system.pkgpaths) }
|
2018-01-29 19:16:29 +01:00
|
|
|
}, f
|
2018-02-01 19:36:09 +01:00
|
|
|
cache: (f) ->
|
|
|
|
_API.handler.packages {
|
2018-03-05 00:20:25 +01:00
|
|
|
command: "cache", args: { paths: (v for k, v of _OS.setting.system.pkgpaths) }
|
2018-02-01 19:36:09 +01:00
|
|
|
}, f
|
2018-03-12 18:55:40 +01:00
|
|
|
setting: (f) ->
|
|
|
|
_API.handler.setting f
|
2018-03-03 13:44:52 +01:00
|
|
|
search: (text) ->
|
|
|
|
r = []
|
|
|
|
|
|
|
|
for k, v of _API.searchHandler
|
|
|
|
ret = _API.searchHandler[k](text)
|
|
|
|
if ret.length > 0
|
|
|
|
ret.unshift { text: k, class: "search-header", dataid: "header" }
|
|
|
|
r = r.concat ret
|
|
|
|
return r
|
|
|
|
|
|
|
|
onsearch: (name, fn) ->
|
2018-03-03 22:27:54 +01:00
|
|
|
self.OS.API.searchHandler[name] = fn unless self.OS.API.searchHandler[name]
|
2018-03-03 13:44:52 +01:00
|
|
|
|
2018-03-10 12:22:01 +01:00
|
|
|
setLocale: (name, f) ->
|
2018-03-09 19:54:33 +01:00
|
|
|
path = "resources/languages/#{name}.json"
|
|
|
|
_API.get path, (d) ->
|
2018-03-10 12:22:01 +01:00
|
|
|
_OS.setting.system.locale = name
|
2018-03-09 19:54:33 +01:00
|
|
|
_API.lang = d
|
2018-03-10 15:40:25 +01:00
|
|
|
if f then f() else _courrier.trigger "systemlocalechange", name
|
2018-03-09 19:54:33 +01:00
|
|
|
, (e, s) ->
|
2018-03-10 12:22:01 +01:00
|
|
|
#_OS.setting.system.locale = "en_GB"
|
2018-03-09 19:54:33 +01:00
|
|
|
_courrier.oserror __("Language file {0} not found", path), e, s
|
2018-03-10 12:22:01 +01:00
|
|
|
f() if f
|
2018-03-09 19:54:33 +01:00
|
|
|
, "json"
|
|
|
|
|
2018-01-24 01:03:14 +01:00
|
|
|
throwe: (n) ->
|
|
|
|
err = undefined
|
|
|
|
try
|
|
|
|
throw new Error(n)
|
|
|
|
catch e
|
|
|
|
err = e
|
|
|
|
return "" if not err
|
2018-03-12 22:47:23 +01:00
|
|
|
return err
|
|
|
|
# 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
|