add services

This commit is contained in:
Xuan Sang LE
2017-08-15 02:56:04 +02:00
parent 2985689217
commit 16074ac3f8
39 changed files with 7912 additions and 188 deletions

View File

@ -1,66 +1,67 @@
self = this
_PM = self.OS.PM
_APP = self.OS.APP
class BaseApplication
class BaseApplication
constructor: (@name) ->
@observable = riot.observable()
@pid = 0
@_api = self.OS.API
init: ->
me = @
# first register some base event to the app
@on "exit", ()-> me.quit()
@on "focus", () ->
me.sysdock.set "selectedApp", me
@on "exit", () -> me.quit()
@on "focus", () ->
me.sysdock.set "selectedApp", me
me.appmenu.pid = me.pid
me.appmenu.set "items", (me.baseMenu() || [])
me.appmenu.set "onmenuselect", (d)->
me.trigger("menuselect",d)
@on "hide", ()->
me.appmenu.set "onmenuselect", (d) ->
me.trigger("menuselect", d)
@on "hide", () ->
me.sysdock.set "selectedApp", null
me.appmenu.set "items",[]
me.appmenu.set "items", []
@on "menuselect", (item) ->
switch item.data.dataid
when "#{me.name}-about" then alert "About " + me.pid + me.name
when "#{me.name}-exit" then me.trigger "exit"
#now load the scheme
path = "packages/#{@name}/scheme.html"
_GUI.loadScheme path ,this
_GUI.loadScheme path , @
on: (e,f) -> @observable.on e,f
on: (e, f) -> @observable.on e, f
trigger:(e,d) -> @observable.trigger e,d
trigger: (e, d) -> @observable.trigger e, d
show: () ->
@observable.trigger "focus"
blur: () ->
@.appmenu.set "items",[] if @.appmenu and @.pid == @.appmenu.pid
@.appmenu.set "items", [] if @.appmenu and @.pid == @.appmenu.pid
@observable.trigger "blur"
hide: () ->
@observable.trigger "hide"
toggle:() ->
toggle: () ->
@observable.trigger "toggle"
quit: () ->
evt = new _GUI.BaseEvent("exit")
@exit(evt)
if not evt.prevent
@.appmenu.set "items",[] if @.pid == @.appmenu.pid
_PM.kill(@)
@.appmenu.set "items", [] if @.pid == @.appmenu.pid
_PM.kill @
($ @scheme).remove()
find: (id) -> ($ "[data-id='#{id}']",@scheme)[0]
find: (id) -> ($ "[data-id='#{id}']", @scheme)[0]
baseMenu:->
baseMenu: ->
menu =
[{
text:_APP[@name].meta.name,
child:[
{text:"About", dataid:"#{@name}-about"},
{text:"Exit", dataid:"#{@name}-exit"}
text: _APP[@name].meta.name,
child: [
{ text: "About", dataid: "#{@name}-about" },
{ text: "Exit", dataid: "#{@name}-exit" }
]
}]
menu = menu.concat @menu() || []
@ -85,4 +86,5 @@ class BaseApplication
# to handle the exit event
# use e.preventDefault() to
# discard the quit command
this.OS.GUI.BaseApplication = BaseApplication
BaseApplication.type = 1
this.OS.GUI.BaseApplication = BaseApplication

View File

@ -0,0 +1,40 @@
MAIL = this.OS.courrier
_API = this.OS.API
_PM = this.OS.PM
class BaseService
constructor: (@name) ->
@icon = undefined
@iconclass = "fa-paper-plane-o"
@text = ""
@_api = _API
@timer = undefined
@holder = undefined
init: ()->
#implement by user
# event registe, etc
# scheme loader
attach: (h) -> @holder = h
update: () -> @holder.update() if @holder
on: (e, f) -> MAIL.on e, f
trigger: (e, d) -> MAIL.trigger e, d
watch: ( t, f) ->
me = @
func = () ->
f()
me.timer = setTimeout (() -> func()), t
func()
quit: ()->
console.log "clean timer" if @timer
clearTimeout @timer if @timer
@cleanup()
_PM.kill @
main: () ->
show: () ->
awake: () ->
#implement by user to tart the service
cleanup:() ->
#implemeted by user
BaseService.type = 2
this.OS.GUI.BaseService = BaseService

View File

@ -1,20 +1,20 @@
self.OS.GUI =
init: () ->
query =
query =
path: 'VFS/get'
data: "#{_GUI.tagPath}/tags.json"
self.OS.API.request query, ()->
loadScheme: (path,app) ->
_API.get path,
loadScheme: (path, app) ->
_API.get path,
(x) ->
return null unless x
scheme = $.parseHTML x
($ "#desktop").append scheme
riot.mount ($ scheme), {observable:app.observable}
riot.mount ($ scheme), { observable: app.observable }
app.scheme = scheme[0]
app.show()
app.main()
app.show()
, (f) ->
alert "cannot load scheme"
@ -23,29 +23,46 @@ self.OS.GUI =
$ "head link#ostheme"
.attr "href", path
pushService: (srv) ->
return _PM.createProcess srv, _APP[srv] if _APP[srv]
path = "services/#{srv}.js"
$.getScript path
.done (e, s) ->
_PM.createProcess srv, _APP[srv]
.fail (e, s) ->
_courrier.trigger "fail",
{ m: "Cannot read service script: #{srv} ",
e: e, s: s }
launch: (app) ->
if not _APP[app]
# first load it
path = "packages/#{app}/"
$.getScript path + "main.js"
.done (e,s) ->
.done (e, s) ->
#load css file
$.get "#{path}main.css", () ->
$ '<link>', {rel:'stylesheet', type:'text/css', 'href':"#{path}main.css"}
$ '<link>', { rel: 'stylesheet', type: 'text/css', 'href': "#{path}main.css" }
.appendTo 'head'
#launch
if _APP[app]
# load app meta data
_API.get "#{path}package.json",
(data) ->
_APP[app].meta = data
_APP[app].meta = data
_PM.createProcess app, _APP[app]
console.log "Fist time loading "+app
,(e,s)->
alert "cannot read application, meta-data"
console.log "Fist time loading " + app
, (e, s) ->
_courrier.trigger "fail",
{ m: "Cannot read application metadata: #{app} ",
e: e, s: s }
alert "cannot read application, meta-data"
.fail (e,s) ->
#BUG report here
console.log "bug report"
_courrier.trigger "fail",
{ m: "Cannot load application script: #{app}",
e: e, s:s }
console.log "bug report", e, s, path
else
# now launch it
if _APP[app]
@ -53,57 +70,54 @@ self.OS.GUI =
dock: (app,meta) ->
# dock an application to a dock
# create a data object
data =
icon:null
iconclass:meta.iconclass||""
data =
icon: null
iconclass: meta.iconclass || ""
app:app
onbtclick:() ->
onbtclick: () ->
app.toggle()
data.icon = "packages/#{meta.app}/#{meta.icon}" if meta.icon
data.iconclass = "fa fa-cogs" if (not meta.icon) and (not meta.iconclass)
dock = $ "#sysdock"
dock.get(0).newapp data
app.sysdock = dock.get(0)
app.appmenu = ($ "[data-id = 'appmenu']","#syspanel")[0]
app.appmenu = ($ "[data-id = 'appmenu']", "#syspanel")[0]
app.init()
#app.show() -- notwork, sice the scheme is not loaded yet
undock: (app) ->
($ "#sysdock").get(0).removeapp app
attachservice: (srv) ->
($ "#syspanel")[0].attachservice srv
srv.init()
detachservice: (srv) ->
($ "#syspanel")[0].detachservice srv
bindContextMenu: (event) ->
handler = (e) ->
if e.contextmenuHandler
e.contextmenuHandler event, ($ "#contextmenu")[0]
else
#console.log ($ "#workspace").get(0), ($ e).parent().get(0)
p = $(e).parent().get(0)
handler p if p isnt ($ "#workspace").get(0)
handler event.target
event.preventDefault()
initDM: ->
_API.resource "schemes/dm.html", (x) ->
return null unless x
scheme = $.parseHTML x
scheme = $.parseHTML x
($ "#wrapper").append scheme
($ "#desktop").on "click", (e)->
return if e.target isnt ($ "#desktop").get(0)
($ "#sysdock").get(0).set "selectedApp",null
osmenu = {child:[
{text:"",iconclass:"fa fa-eercast", child:[
{text:"About"},
{text:"System Preferences", iconclass:"fa fa-commenting"},
{text:"Applications",child:[
{text:"Terminal",type:"app"},
{text:"NotePad",type:"app", icon:"packages/NotePad/icon.png"},
{text:"ActivityMonitor",type:"app"}
]},
{text:"Logout"}
]}
],onmenuselect: (item)->
switch item.data.type
when "app" then _GUI.launch item.data.text
}
appmenu = {child:[]}
systray = {child:[
{text:"Sun 22:57 6 August 2017"},
{text:"",iconclass:"fa fa-search"},
{text:"",iconclass:"fa fa-commenting"}
],onmenuselect: (item)->
console.log item
}
riot.mount ($ "#syspanel", $ "#wrapper"),{osmenu:osmenu,appmenu:appmenu,systray:systray}
riot.mount ($ "#sysdock", $ "#wrapper"), {items:[]}
# context menu
riot.mount ($ "#contextmenu")
($ "#workspace").contextmenu (e) -> _GUI.bindContextMenu e
#desktop
desktop = ($ "#desktop")
desktop.on "click", (e) ->
return if e.target isnt desktop.get(0)
($ "#sysdock").get(0).set "selectedApp", null
desktop.get(0).contextmenuHandler = (e, m) ->
console.log "context menu handler for desktop"
# system menu
riot.mount ($ "#syspanel", $ "#wrapper")
riot.mount ($ "#sysdock", $ "#wrapper"), { items: [] }

View File

@ -6,3 +6,4 @@
<div id = "desktop">
</div>
</div>
<afx-menu id="contextmenu" context="true" style="display:none;"></afx-menu>

View File

@ -39,10 +39,6 @@
{
return self[k]
}
self.root.update = function()
{
self.update()
}
minimize()
{
this.root.observable.trigger("hide")
@ -108,6 +104,7 @@
else
self.root.observable.trigger("focus")
})
self.root.observable.trigger("loaded", self.root)
})
var enable_dragging = function()
{

View File

@ -51,10 +51,9 @@
{
return self[k]
}
self.root.update = function()
{
self.update()
}
this.on("mount", function(){
window.OS.courrier.trigger("sysdockloaded")
})
</script>
</afx-apps-dock>

View File

@ -23,10 +23,6 @@
{
return self[k]
}
self.root.update = function()
{
self.update()
}
this._onbtclick = function(e)
{
if(typeof opts.onbtclick == 'string')

View File

@ -82,7 +82,6 @@
data:event.item}
if(opts.onlistselect)
opts.onlistselect(data)
console.log(data)
if(self.selidx != -1)
self.rows[self.selidx].selected =false
self.selidx = event.item.i

View File

@ -4,23 +4,6 @@
</div>
<script>
var self = this
self.root.set = function(k,v)
{
if(k == "*")
for(var i in v)
self[i] = v[i]
else
self[k] = v
self.update()
}
self.root.get = function(k)
{
return self[k]
}
self.root.update = function()
{
self.update()
}
this.on('mount', function(){
$(self.refs.container)
.css("display","flex")
@ -44,6 +27,7 @@
var auto_height = []
var csize, ocheight = 0, avaiheight;
avaiheight = $(self.root).parent().height()
avaiwidth = $(self.root).parent().width()
$(self.refs.container).css("height",avaiheight + "px")
$(self.refs.container)
.children()
@ -69,6 +53,8 @@
{
$(v).css("height", csize + "px")
})
self.root.observable.trigger("hboxchange",
{id:$(self.root).attr("data-id"), w:avaiwidth, h:csize})
}
</script>
</afx-hbox>

View File

@ -28,10 +28,6 @@
self[k] = v
self.update()
}
self.root.update = function()
{
self.update()
}
self.root.get = function(k)
{
if(k == "selected")
@ -69,7 +65,6 @@
{
var desktoph = $("#desktop").height()
var off = $(self.root).offset().top + $(self.refs.mlist).height()
console.log(desktoph,off)
if( off > desktoph )
$(self.refs.mlist)
.css("top","-" + $(self.refs.mlist).outerHeight() + "px")

View File

@ -1,23 +1,30 @@
<afx-menu>
<ul>
<afx-menu >
<ul class={context: opts.context == "true"}>
<li class="afx-corner-fix"></li>
<li each={ items } class = {afx_submenu:child != null, fix_padding:icon}>
<li ref = "container" each={ item,i in items } class = {afx_submenu:item.child != null, fix_padding:item.icon} no-reorder>
<a href="#" onclick = {parent.onselect}>
<i if={iconclass} class = {iconclass} ></i>
<i if={icon} class="icon-style" style = { "background: url("+icon+");background-size: 100% 100%;background-repeat: no-repeat;" }></i>
{ text }
<i if={item.iconclass} class = {item.iconclass} ></i>
<i if={item.icon} class="icon-style" style = { "background: url("+item.icon+");background-size: 100% 100%;background-repeat: no-repeat;" }></i>
{ item.text }
</a>
<afx-menu if={child != null} child={child} onmenuselect={onmenuselect} observable = {parent.root.observable} rootid = {parent.rid}></afx-menu>
<afx-menu if={item.child != null} child={item.child} observable = {parent.root.observable} rootid = {parent.rid}></afx-menu>
</li>
<li class="afx-corner-fix"></li>
</ul>
<script>
this.items = opts.child
this.items = opts.child || []
var isRoot
if(opts.rootid)
{
this.rid = opts.rootid
else
isRoot = false
}
else
{
this.rid = $(this.root).attr("data-id")
isRoot = true
}
var self = this
this.onmenuselect = opts.onmenuselect
self.root.set = function(k,v)
@ -29,14 +36,45 @@
self[k] = v
self.update()
}
self.root.get = function(k)
self.root.push = function(e,u)
{
return self[k]
self.items.push(e)
if(u)
self.update()
}
self.root.unshift = function(e,u)
{
self.items.unshift(e)
if(u)
self.update()
}
self.root.remove = function(e,u)
{
var i = self.items.indexOf(e)
if(i >= 0)
self.items.splice(i, 1)
if(u)
self.update()
}
self.root.update = function()
{
self.update()
}
self.root.get = function(k)
{
return self[k]
}
self.root.show = function(e)
{
//only for menucontext
if(opts.context != "true") return;
$(self.root)
.css("top", e.clientY - 15 + "px")
.css("left",e.clientX -5 + "px")
.show()
$(document).on("click",mnhide)
}
if(opts.observable)
{
this.root.observable = opts.observable
@ -47,23 +85,61 @@
this.root.observable.on('menuselect',function(data){
//console.log("From root",self.root)
if(self.onmenuselect)
{
self.onmenuselect(data)
if(opts.context == "true")
$(self.root).hide()
else if(!data.root && self.refs.container)
{
var arr = self.refs.container.length?self.refs.container:[self.refs.container]
for( var i in arr)
$("afx-menu",arr[i]).first().hide()
}
})
}
var mnhide = function(event)
{
if(opts.context == "true")
{
if(!$(event.target).closest(self.root).length) {
$(self.root).hide()
$(document).unbind("click",mnhide)
}
return;
}
if(!$(event.target).closest(self.refs.container).length && self.refs.container) {
var arr = self.refs.container.length?self.refs.container:[self.refs.container]
for( var i in arr)
$("afx-menu",arr[i]).first().hide()
$(document).unbind("click",mnhide)
}
else
{
if(self.refs.container && self.refs.container.length)
for(var i in self.refs.container)
if(!$(event.target).closest(self.refs.container[i]).length) {
$("afx-menu",self.refs.container[i]).first().hide()
}
}
}
onselect(event)
{
var data = {id:self.rid, data:event.item}
/*if(self.onmenuselect)
{
self.onmenuselect(data)
} else*/
var data = {id:self.rid, data:event.item.item, root:isRoot}
this.root.observable.trigger('menuselect',data)
event.preventDefault()
event.preventDefault()
$(document).unbind("click",mnhide)
if(opts.context == "true") return
if(isRoot && self.refs.container)
{
if(self.refs.container.length)
$("afx-menu",self.refs.container[event.item.i]).first().show()
else
$("afx-menu",self.refs.container).first().show()
$(document).on("click",mnhide)
return
}
}
</script>

View File

@ -0,0 +1,3 @@
<afx-service>
<yield/>
</afx-service>

View File

@ -1,16 +1,42 @@
<afx-sys-panel>
<div>
<afx-menu data-id = "os_menu" ref = "aOsmenu" child={osmenu.child} onmenuselect = {osmenu.onmenuselect} class="afx-panel-os-menu"></afx-menu>
<afx-menu data-id = "appmenu" ref = "aAppmenu" child={appmenu.child} onmenuselect = {appmenu.onmenuselect} class = "afx-panel-os-app"></afx-menu>
<afx-menu data-id = "appmenu" ref = "aAppmenu" child={appmenu.child} class = "afx-panel-os-app"></afx-menu>
<afx-menu data-id = "sys_tray" ref = "aTray" child={systray.child} onmenuselect = {systray.onmenuselect} class = "afx-panel-os-stray"></afx-menu>
</div>
<script>
this.osmenu = opts.osmenu
this.appmenu = opts.appmenu
this.systray = opts.systray
this.osmenu = {child:[
{text:"",iconclass:"fa fa-eercast", child:[
{text:"About"},
{text:"System Preferences", iconclass:"fa fa-commenting"},
{text:"Applications",child:[
{text:"wTerm",type:"app"},
{text:"NotePad",type:"app", iconclass:"fa fa-commenting"},
{text:"ActivityMonitor",type:"app"},
{text:"DummyApp",type:"app"}
]},
{text:"Logout"}
]}
],onmenuselect: function(item)
{
if(item.data.type == "app")
window.OS.GUI.launch(item.data.text)
}
}
this.appmenu = { child: [] }
this.systray = { child: [], onmenuselect: function(item){item.data.awake()}}
var self = this
self.root.attachservice = function(s)
{
s.attach(self.refs.aTray)
self.refs.aTray.root.unshift(s,true)
}
self.root.detachservice = function(s)
{
self.refs.aTray.root.remove(s, true)
}
self.root.set = function(k,v)
{
if(k == "*")
@ -24,15 +50,12 @@
{
return self[k]
}
self.root.update = function()
{
self.update()
}
this.on('mount', function() {
//console.log(self.refs.aOsmenu.root)
$(self.refs.aOsmenu.root).css("z-index",1000000)
$(self.refs.aAppmenu.root).css("z-index",1000000)
$(self.refs.aTray.root).css("z-index",1000000)
window.OS.courrier.trigger("syspanelloaded")
})
</script>
</afx-sys-panel>

View File

@ -49,10 +49,6 @@
self[k] = v
self.update()
}
self.root.update = function()
{
self.update()
}
self.root.get = function(k)
{
return self[k]

View File

@ -4,23 +4,6 @@
</div>
<script>
var self = this
self.root.set = function(k,v)
{
if(k == "*")
for(var i in v)
self[i] = v[i]
else
self[k] = v
self.update()
}
self.root.get = function(k)
{
return self[k]
}
self.root.update = function()
{
self.update()
}
this.on('mount', function(){
$(self.refs.container)
.css("display","flex")
@ -36,7 +19,6 @@
})
}
})
var calibrate_size = function()
{
var auto_width = []
@ -51,6 +33,7 @@
this.observable = self.root.observable
$(this)
.css("flex-grow","1")
//.css("height",avaiheight + "px")
var dw = $(this).attr("data-width")
if(dw)
{
@ -67,6 +50,8 @@
{
$(v).css("width", csize + "px")
})
self.root.observable.trigger("vboxchange",
{id:$(self.root).attr("data-id"), w:csize, h:avaiheight})
}
</script>
</afx-vbox>

View File

@ -66,7 +66,7 @@ afx-menu afx-menu li{
float:none;
min-width: 150px;
}
afx-menu afx-menu afx-menu{
afx-menu afx-menu afx-menu, afx-menu ul.context afx-menu{
top:-4px;
left: 100%;
}
@ -78,7 +78,7 @@ afx-menu li:hover > a {
color: white;
}
afx-menu li:hover > afx-menu
afx-menu afx-menu li:hover > afx-menu, ul.context li:hover > afx-menu
{
display: block;
}
@ -92,7 +92,7 @@ afx-menu li.afx-corner-fix:hover{
background-color: transparent;
}
afx-menu afx-menu .afx_submenu:before {
afx-menu afx-menu .afx_submenu:before, afx-menu ul.context .afx_submenu:before{
content: "\f054";
font-family: "FontAwesome";
font-size: 10px;
@ -101,3 +101,19 @@ afx-menu afx-menu .afx_submenu:before {
position:absolute;
top:25%;
}
afx-menu ul.context{
position: absolute;
z-index: 1000000;
padding: 0;
border:1px solid #a6a6a6;
border-radius: 5px;
border-top-left-radius: 0px;
/*box-shadow: 2px 2px 2px #cbcbcb;*/
box-shadow: 1px 1px 1px #9f9F9F;
background-color: #e7e7e7;
}
afx-menu ul.context li{
clear:float;
min-width: 150px;
}