use services to communicate between apps

This commit is contained in:
Xuan Sang LE
2017-08-16 00:27:32 +02:00
parent 16074ac3f8
commit 8fbd0b4a98
62 changed files with 590 additions and 211 deletions

View File

@ -1,16 +1,15 @@
self = this
_PM = self.OS.PM
_APP = self.OS.APP
class BaseApplication
constructor: (@name) ->
@observable = riot.observable()
@pid = 0
@_api = self.OS.API
_MAIL = self.OS.courrier
class BaseApplication extends this.OS.GUI.BaseModel
constructor: (name) ->
super name
init: ->
me = @
# first register some base event to the app
@on "exit", () -> me.quit()
@on "focus", () ->
me.sysdock.set "selectedApp", me
me.appmenu.pid = me.pid
@ -20,41 +19,33 @@ class BaseApplication
@on "hide", () ->
me.sysdock.set "selectedApp", null
me.appmenu.set "items", []
@on "menuselect", (item) ->
switch item.data.dataid
@on "menuselect", (d) ->
switch d.e.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 , @
@.render path
on: (e, f) -> @observable.on e, f
trigger: (e, d) -> @observable.trigger e, d
show: () ->
@observable.trigger "focus"
@trigger "focus"
blur: () ->
@.appmenu.set "items", [] if @.appmenu and @.pid == @.appmenu.pid
@observable.trigger "blur"
@trigger "blur"
hide: () ->
@observable.trigger "hide"
@trigger "hide"
toggle: () ->
@observable.trigger "toggle"
@trigger "toggle"
quit: () ->
evt = new _GUI.BaseEvent("exit")
@exit(evt)
onexit: (evt) ->
@cleanup(evt)
if not evt.prevent
@.appmenu.set "items", [] if @.pid == @.appmenu.pid
_PM.kill @
($ @scheme).remove()
find: (id) -> ($ "[data-id='#{id}']", @scheme)[0]
baseMenu: ->
menu =
[{
@ -81,7 +72,7 @@ class BaseApplication
# to return app data
update:->
#implement by subclasses
exit: (e) ->
cleanup: (e) ->
#implement by subclasses
# to handle the exit event
# use e.preventDefault() to

50
src/core/BaseModel.coffee Normal file
View File

@ -0,0 +1,50 @@
self = this
_PM = self.OS.PM
_APP = self.OS.APP
_MAIL = self.OS.courrier
_GUI = self.OS.GUI
class BaseModel
constructor: (@name) ->
@observable = riot.observable()
@pid = 0
@_api = self.OS.API
me = @
@on "exit", () -> me.quit()
@parent = "#desktop"
render: (p) ->
_GUI.loadScheme p, @, @parent
quit: () ->
evt = new _GUI.BaseEvent("exit")
@onexit(evt)
if not evt.prevent
delete @.observable
_PM.kill @
init: ->
#implement by sub class
onexit: (e) ->
#implement by subclass
on: (e, f) -> @observable.on e, f
trigger: (e, d) -> @observable.trigger e, d
subscribe: (e, f) -> _MAIL.on e, f, @
meta: () -> _APP[@name].meta
publish: (t, m) ->
mt = @meta()
_MAIL.trigger t, { id: @pid, name: @name, data: { m: m, icon: mt.icon, iconclass: mt.iconclass } }
notify: (m) ->
@publish "notification", m
warn: (m) ->
@publish "warning", m
error: (m) ->
@publish "error", m
fail: (m) ->
@publish "fail", m
find: (id) -> ($ "[data-id='#{id}']", @scheme)[0] if @scheme
this.OS.GUI.BaseModel = BaseModel

View File

@ -1,12 +1,11 @@
MAIL = this.OS.courrier
_API = this.OS.API
_PM = this.OS.PM
class BaseService
constructor: (@name) ->
class BaseService extends this.OS.GUI.BaseModel
constructor: (name) ->
super name
@icon = undefined
@iconclass = "fa-paper-plane-o"
@text = ""
@_api = _API
@timer = undefined
@holder = undefined
@ -15,26 +14,29 @@ class BaseService
# event registe, etc
# scheme loader
attach: (h) -> @holder = h
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: ()->
onexit: (evt) ->
console.log "clean timer" if @timer
clearTimeout @timer if @timer
@cleanup()
_PM.kill @
@cleanup(evt)
($ @scheme).remove() if @scheme
main: () ->
show: () ->
awake: () ->
awake: (e) ->
#implement by user to tart the service
cleanup:() ->
cleanup: (evt) ->
#implemeted by user
BaseService.type = 2
BaseService.singleton = true
this.OS.GUI.BaseService = BaseService

View File

@ -5,21 +5,19 @@ self.OS.API =
handler: new Object()
#request a user data
request: (query,callback) ->
request: (query, callback) ->
# definition here
handle.request query,callback
handle.request query, callback
systemConfig: ->
_API.request 'config', (result) ->
console.log result
get:(p,c,f)->
$.get p
.done (data) ->
c(data)
.fail ->
f()
resource: (resource,callback) ->
get: (p, c, f) ->
$.get p
.done (data) -> c(data)
.fail -> f()
resource: (resource, callback) ->
path = "resources/#{resource}"
_API.get path,callback
_API.get path, callback

69
src/core/core.coffee Normal file
View File

@ -0,0 +1,69 @@
#define the OS object
self = this
self.OS or=
API: new Object()
GUI: new Object()
APP: new Object()
courrier:
observable: riot.observable()
listeners: new Object
on: (e, f, a) ->
_courrier.listeners[a.pid] = [] unless _courrier.listeners[a.pid]
_courrier.listeners[a.pid].push { e: e, f: f }
_courrier.observable.on e, f
trigger: (e, d) -> _courrier.observable.trigger e, d
unregister: (app) ->
return unless _courrier.listeners[app.pid] and _courrier.listeners[app.pid].length > 0
_courrier.observable.off i.e, i.f for i in _courrier.listeners[app.pid]
delete _courrier.listeners[app.pid]
_courrier.listeners[app.pid] = []
register: (name, x) -> _APP[name] = x
PM:
pidalloc: 0
processes: new Object
createProcess: (app, cls) ->
#if it is single ton
# and a process is existing
# just return it
if cls.singleton and _PM.processes[app] and _PM.processes[app].length == 1
_PM.processes[app][0].show()
else
_PM.processes[app] = [] if not _PM.processes[app]
obj = new cls
obj.birth = (new Date).getTime()
_PM.pidalloc++
obj.pid = _PM.pidalloc
_PM.processes[app].push obj
if cls.type is 1 then _GUI.dock obj, cls.meta else _GUI.attachservice obj
if cls.type is 2
_courrier.trigger "srvroutineready", app
appByPid: (pid) ->
app = undefined
find = (l) ->
return a for a in l when a.pid is pid
for k, v of _PM.processes
app = find v
break if app
app
kill: (app) ->
return if not _PM.processes[app.name]
i = _PM.processes[app.name].indexOf app
if i >= 0
if _APP[app.name].type == 1 then _GUI.undock app else _GUI.detachservice app
_courrier.unregister app
delete _PM.processes[app.name][i]
_PM.processes[app.name].splice i, 1
boot: ->
#first load the configuration
#then load the theme
_GUI = self.OS.GUI
_GUI.loadTheme "antos"
_GUI.initDM()
_courrier.observable.one "syspanelloaded", () ->
_GUI.pushServices ["PushNotification", "Spotlight", "Calendar"]

View File

@ -5,17 +5,22 @@ self.OS.GUI =
data: "#{_GUI.tagPath}/tags.json"
self.OS.API.request query, ()->
loadScheme: (path, app) ->
loadScheme: (path, app, parent) ->
_API.get path,
(x) ->
return null unless x
scheme = $.parseHTML x
($ "#desktop").append scheme
($ parent).append scheme
riot.mount ($ scheme), { observable: app.observable }
app.scheme = scheme[0]
app.main()
app.show()
, (f) ->
_courrier.trigger "fail",
{id: 0, data: {
m: "Cannot load scheme file: #{path} for #{app.name} (#{app.pid})",e: e, s: s },
name:"OS"
}
alert "cannot load scheme"
loadTheme: (name) ->
@ -23,6 +28,13 @@ self.OS.GUI =
$ "head link#ostheme"
.attr "href", path
pushServices: (srvs) ->
f = (v) ->
_courrier.observable.one "srvroutineready", () -> _GUI.pushService v
_GUI.pushService srvs[0]
srvs.splice 0, 1
f i for i in srvs
pushService: (srv) ->
return _PM.createProcess srv, _APP[srv] if _APP[srv]
path = "services/#{srv}.js"
@ -30,9 +42,10 @@ self.OS.GUI =
.done (e, s) ->
_PM.createProcess srv, _APP[srv]
.fail (e, s) ->
_courrier.trigger "srvroutineready", srv
_courrier.trigger "fail",
{ m: "Cannot read service script: #{srv} ",
e: e, s: s }
{ id:0,data:{m: "Cannot read service script: #{srv} ", e: e, s: s },
name:"0S"}
launch: (app) ->
if not _APP[app]
@ -54,14 +67,13 @@ self.OS.GUI =
console.log "Fist time loading " + app
, (e, s) ->
_courrier.trigger "fail",
{ m: "Cannot read application metadata: #{app} ",
e: e, s: s }
{id:0, data:{ m: "Cannot read application metadata: #{app} ",e: e, s: s }, name:"OS"}
alert "cannot read application, meta-data"
.fail (e,s) ->
#BUG report here
_courrier.trigger "fail",
{ m: "Cannot load application script: #{app}",
e: e, s:s }
{id :0, data:{m: "Cannot load application script: #{app}",
e: e, s:s }, name:"OS"}
console.log "bug report", e, s, path
else
# now launch it

View File

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

View File

@ -1,72 +0,0 @@
afx-app-window div.afx-window-wrapper{
border:1px solid #a6a6a6;
/*box-shadow: 1px 1px 1px #cbcbcb;*/
box-shadow: 1px 1px 1px #9f9F9F;
border-radius: 5px;
background-color:#dfdfdf;
padding:0;
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
}
afx-app-window.unactive > div.afx-window-wrapper{
background-color: #f6f6f6;
}
afx-app-window ul.afx-window-top{
margin: 0;
padding: 0;
width: 100%;
padding:0;
height: 20px;
border-bottom: 1px solid #a6a6a6;
}
afx-app-window ul.afx-window-top li{
list-style: none;
margin-left: 3px;
margin-top:4px;
}
afx-app-window ul.afx-window-top .afx-window-close,.afx-window-minimize,.afx-window-maximize{
width: 11px;
height: 11px;
border-radius: 10px;
}
afx-app-window ul li.afx-window-close{
background-color: #Fc605b;
float:left;
}
afx-app-window ul li.afx-window-minimize{
background-color: #fec041;
float:left;
}
afx-app-window ul li.afx-window-maximize{
background-color: #35cc4b;
float:left;
}
afx-app-window ul li.afx-window-title{
margin-top:1px;
float:none;
overflow: hidden;
padding-left: 5px;
padding-right: 5px;
text-align: center;
}
afx-app-window div.afx-window-content
{
overflow: hidden;
width: 100%;
background-color: white;
flex-grow: 1;
border-bottom-left-radius: 5px;
border-bottom-right-radius: 5px;
}
afx-app-window div.afx-window-grip{
height: 10px;
width: 10px;
background-color: transparent;
}

View File

@ -1,25 +0,0 @@
afx-button button{
outline: none;
padding: 4px;
border: 1px solid #a6a6a6;
background-color: white;
color: #414339;
border-radius: 6px;
font-family: "Ubuntu";
font-size: 13px;
}
afx-button button[disabled]{
color: #a6a6a6;
}
afx-button i.icon-style {
width: 16px;
height: 16px;
display: inline-block;
float:left;
}
afx-button button:active {
background-color: #2786F3;
color: white;
border: 1px solid #dedede;
}

View File

@ -1,36 +0,0 @@
afx-apps-dock{
float: left;
bottom: 3px;
top: 3px;
width: 32px;
background-color:#e7e7e7;
position: absolute;
padding:2px;
padding-top: 5px;
border-top-right-radius: 5px;
border-bottom-right-radius: 5px;
border:1px solid #a6a6a6;
overflow: hidden;
box-shadow: 1px 1px 1px #9f9F9F;
}
afx-apps-dock afx-button button{
width: 32px;
height: 32px;
font-size: 19px;
margin-bottom: 3px;
padding:0px;
background-color: transparent;
border:0;
}
afx-apps-dock afx-button .icon-style{
width: 24px;
height: 24px;
margin-bottom: 0px;
border:0;
}
afx-apps-dock afx-button.selected > button {
background-color: #2786F3;
color: white;
border: 1px solid #dedede;
}

View File

@ -1,33 +0,0 @@
afx-grid-view{
overflow: hidden;
padding:5px;
}
afx-grid-view afx-grid-row div{
padding:3px;
padding-left: 5px;
padding-right: 5px;
}
afx-grid-view afx-grid-row:nth-child(even){
background-color: #f5F5F5;
}
afx-grid-view afx-grid-row.grid_row_header div{
border-right: 2px solid #e5e5e5;
}
afx-grid-view afx-grid-row i.icon-style {
width: 16px;
height: 16px;
display: inline-block;
float:left;
}
afx-grid-view afx-grid-row.selected {
background-color: #116cd6;
color:white;
}
afx-grid-view afx-grid-row.grid_row_header {
font-weight: bold;
border: 1px solid #e5e5e5;
border-right:0;
}

View File

@ -1,104 +0,0 @@
afx-list-view{
overflow:auto;
padding: 5px;
}
/*
afx-list-view div.list-container{
width: 100%;
height: 100%;
display: inline-block;
position: relative;
background-color: red;
}*/
afx-list-view ul{
margin:0;
padding: 0;
}
afx-list-view li{
margin:0;
padding:0;
list-style: none;
padding: 5px;
padding-top:3px;
padding-bottom: 3px;
color: #414339;
background-color: white;
}
afx-list-view li:nth-child(odd){
background-color: #f5F5F5;
}
afx-list-view i.icon-style {
width: 16px;
height: 16px;
display: inline-block;
float:left;
}
afx-list-view li > i {
margin-right: 3px;
}
afx-list-view li.selected {
background-color: #116cd6;
color:white;
}
/*
afx-list-view.dropdown div.list-container{
position: relative;
display: inline-block;
}
afx-list-view.dropdown div.list-container ul{
position:absolute;
top:100%;
left:0;
display: none;
border:1px solid red;
}*/
afx-list-view.dropdown {
padding:0;
margin: 0;
}
afx-list-view.dropdown div.list-container ul{
max-height: 150px;
overflow-y: auto;
overflow-x: hidden;
background-color: white;
}
afx-list-view.dropdown div.list-container ul{
border:1px solid #a6a6a6;
box-shadow: 1px 1px 1px #9f9F9F;
border-radius: 3px;
padding:2px;
border-top-left-radius: 0px;
}
afx-list-view.dropdown div.list-container ul li{
display: inline-block;
width:100%;
}
afx-list-view.dropdown div.list-container div{
padding:3px;
border:1px solid #a6a6a6;
border-radius: 3px;
padding-right:15px;
background-color: white;
height: 17px;
}
afx-list-view.dropdown div.list-container div:before {
content: "\f107";
font-family: "FontAwesome";
font-size: 11px;
font-style: normal;
color: #414339;
position: absolute;
top:25%;
right: 5px;
}
afx-list-view.dropdown div.list-container ul li:hover{
background-color: #dcdcdc;
color: #414339;
}

View File

@ -1,119 +0,0 @@
afx-menu {
position:relative;
display:inline-block;
/*z-index: 100000;*/
}
afx-menu a{
text-decoration: none;
color: #414339;
display: inline-block;
width: 100%;
height: 100%;
}
afx-menu ul{
padding:0;
margin: 0;
}
afx-menu i.icon-style {
width: 16px;
height: 16px;
display: inline-block;
float:left;
}
afx-menu afx-menu ul {
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 > li{
list-style:none;
margin:0;
position: relative;
float: left;
padding:3px;
padding-left: 5px;
padding-right: 5px;
}
afx-menu ul > li.fix_padding{
padding-top:1px;
padding-bottom: 0;
padding-left: 5px;
padding-right: 5px;
}
afx-menu afx-menu ul > li.fix_padding{
padding:3px;
padding-left: 5px;
padding-right: 5px;
}
afx-menu afx-menu {
top:100%;
left:0;
position: absolute;
display:none;
}
afx-menu afx-menu i{
margin-right: 5px;
}
afx-menu afx-menu li{
float:none;
min-width: 150px;
}
afx-menu afx-menu afx-menu, afx-menu ul.context afx-menu{
top:-4px;
left: 100%;
}
afx-menu li:hover {
background-color: #2786F3;
}
afx-menu li:hover > a {
color: white;
}
afx-menu afx-menu li:hover > afx-menu, ul.context li:hover > afx-menu
{
display: block;
}
afx-menu li.afx-corner-fix{
height: 3px;
padding: 0;
margin: 0;
background-color: transparent;
}
afx-menu li.afx-corner-fix:hover{
background-color: transparent;
}
afx-menu afx-menu .afx_submenu:before, afx-menu ul.context .afx_submenu:before{
content: "\f054";
font-family: "FontAwesome";
font-size: 10px;
right:5px;
color: #414339;
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;
}

View File

@ -1,28 +0,0 @@
afx-sys-panel{
padding:0;
margin: 0;
}
afx-sys-panel div{
width: 100%;
height: 23px;
margin:0;
padding: 0;
background-color: #e7e7e7;
border-bottom: 1px solid #9c9C9C;
box-shadow: 1px 1px 1px #9F9F9F;
position:absolute;
}
afx-sys-panel .afx-panel-os-menu{
padding:0;
margin: 0;
float:left;
}
afx-sys-panel .afx-panel-os-stray{
float:right;
}
afx-sys-panel .afx-panel-os-stray afx-menu afx-menu{
top:-4px;
right:0;
}

View File

@ -1,59 +0,0 @@
afx-tree-view{
color: #414339;
padding:3px;
overflow: auto;
}
afx-tree-view afx-tree-view{
padding:0;
overflow: hidden;
}
afx-tree-view ul{
margin:0;
padding:0;
}
afx-tree-view li{
list-style: none;
margin:0;
padding: 0;
}
afx-tree-view div{
padding:3px;
background-color: white;
}
afx-tree-view i.icon-style {
width: 16px;
height: 16px;
display: inline-block;
float:left;
margin-right: 3px;
}
afx-tree-view div.afx_tree_item_selected{
background-color: #116cd6;
color:white;
}
afx-tree-view div.afx_tree_item_selected:hover{
background-color: #116cd6;
color:white;
}
/*
afx-tree-view div:hover{
background-color: #f5F5F5;
color: #414339;
}*/
afx-tree-view .afx_folder_item{
font-weight: bold;
}
afx-tree-view .afx-tree-view-folder-open:before{
content: "\f147";
font-family: "FontAwesome";
font-size: 13px;
}
afx-tree-view .afx-tree-view-folder-close:before{
content: "\f196";
font-family: "FontAwesome";
font-size: 13px;
}
afx-tree-view .afx_tree_item_odd{
background-color: #f5F5F5;
}

View File

@ -1,42 +0,0 @@
html,body{
margin: 0;
padding: 0;
font-family: "Ubuntu";
font-size: 13px;
width: 100%;
height: 100%;
background-image: url(wallpaper.jpg);
background-size: cover;
}
#wrapper{
margin: 0;
padding: 0;
min-height:100%;
overflow:hidden;
}
.afx-clear{
clear:both;
background-color: transparent;
border: 0;
height: 1px;
}
#workspace {
width: 100%;
position: absolute;
bottom: 0;
top: 24px;
}
#desktop{
position: absolute;
top:3px;
bottom: 0;
margin: 0;
left: 40px;
right: 0;
user-select:none;
cursor: default;
padding:0px;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 434 KiB

View File

@ -1,12 +0,0 @@
/*! Generated by Font Squirrel (https://www.fontsquirrel.com) on August 6, 2017 */
@font-face {
font-family: 'HermitLight';
src: url('fonts/hermit-light-webfont.woff2') format('woff2'),
url('fonts/hermit-light-webfont.woff') format('woff');
font-weight: normal;
font-style: normal;
}

View File

@ -1,39 +0,0 @@
/*! Generated by Font Squirrel (https://www.fontsquirrel.com) on August 6, 2017 */
@font-face {
font-family: 'Ubuntu';
src: url('fonts/ubuntu-regular-webfont.woff2') format('woff2'),
url('fonts/ubuntu-regular-webfont.woff') format('woff');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'Ubuntu';
src: url('fonts/ubuntu-bold-webfont.woff2') format('woff2'),
url('fonts/ubuntu-bold-webfont.woff') format('woff');
font-weight: bold;
font-style: normal;
}
@font-face {
font-family: 'Ubuntu';
src: url('fonts/ubuntu-bolditalic-webfont.woff2') format('woff2'),
url('fonts/ubuntu-bolditalic-webfont.woff') format('woff');
font-weight: bold;
font-style: italic;
}
@font-face {
font-family: 'Ubuntu';
src: url('fonts/ubuntu-italic-webfont.woff2') format('woff2'),
url('fonts/ubuntu-italic-webfont.woff') format('woff');
font-weight: normal;
font-style: italic;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 MiB

View File

@ -1,36 +0,0 @@
self.OS.PM =
pidalloc: 0
processes: new Object
createProcess: (app, cls) ->
#if it is single ton
# and a process is existing
# just return it
if cls.singleton and _PM.processes[app] and _PM.processes[app].length == 1
_PM.processes[app][0].show()
return _PM.processes[app][0]
else
_PM.processes[app] = [] if not _PM.processes[app]
obj = new cls
obj.birth = (new Date).getTime()
_PM.pidalloc++
obj.pid = _PM.pidalloc
_PM.processes[app].push obj
if cls.type is 1 then _GUI.dock obj, cls.meta else _GUI.attachservice obj
appByPid:(pid)->
app = undefined
find = (l) ->
return a for a in l when a.pid is pid
for k, v of _PM.processes
app = find v
break if app
app
kill: (app) ->
return if not _PM.processes[app.name]
i = _PM.processes[app.name].indexOf app
if i >= 0
p = _PM.processes[app.name][i]
if _APP[app.name].type == 1 then _GUI.undock p else _GUI.detachservice p
delete _PM.processes[app.name][i]
_PM.processes[app.name].splice i, 1

View File

@ -0,0 +1,36 @@
<afx-dummy>
<afx-overlay data-id = "notifyzone" width = "250">
<afx-list-view data-id="notifylist"></afx-list-view>
<style>
afx-overlay[data-id = "notifyzone"]{
background-color: rgba(215,215,215,0.7);
overflow-y: auto;
overflow-x: hidden;
padding:3px;
margin: 0;
}
afx-list-view[data-id = "notifylist"]
{
padding:0;
}
afx-list-view[data-id = "notifylist"] li{
border:1px solid #a6a6a6;
border-radius: 6px;
margin-bottom: 2px;
}
</style>
</afx-overlay>
<afx-feed data-id = "notifeed" style = "display: none;" closable="true">
<!--afx-button text = "click me"></afx-button-->
<style>
afx-feed[data-id = "notifeed"]{
position: absolute;
width: 250px;
}
afx-feed[data-id = "notifeed"] > div{
box-shadow: 1px 1px 1px #9f9F9F;
}
</style>
</afx-feed>
</afx-dummy>

View File

@ -104,7 +104,7 @@
else
self.root.observable.trigger("focus")
})
self.root.observable.trigger("loaded", self.root)
self.root.observable.trigger("rendered", self.root)
})
var enable_dragging = function()
{

View File

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

35
src/core/tags/afx-feed.js Normal file
View File

@ -0,0 +1,35 @@
<afx-feed>
<div>
<p>
<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>
{header}
<i if={closable} class = "closable"></i>
</p>
<div>
<p>{text}</p>
<yield/>
</div>
</div>
<script>
var self = this
this.icon = opts.icon
this.iconclass = opts.iconclass
this.closable = opts.closable
this.header = opts.header||""
this.text = opts.text || ""
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]
}
</script>
</afx-feed>

View File

@ -8,11 +8,12 @@
<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 = {closable} class = "closable" click = {parent._remove}></i>
</li>
</ul>
</div>
<script>
this.items = opts.child
this.items = opts.child || []
var self = this
self.selidx = -1
self.selectedText = ""
@ -34,7 +35,16 @@
return self.items[self.selidx]
return self[k]
}
self.root.push = function(e,u)
{
self.items.push(e)
if(u) self.update()
}
self.root.unshift = function(e,u)
{
self.items.unshift(e)
if(u) self.update()
}
if(opts.observable)
this.root.observable = opts.observable
else
@ -72,6 +82,17 @@
$(self.refs.mlist).css("top","100%")
$(self.refs.mlist).show()
}
_remove(event)
{
if(self.selidx != -1)
{
self.items[self.selidx].selected =false
self.selidx = -1
}
self.items.splice(self.items.indexOf(event.item),1)
event.target = self.root
self.update()
}
_select(event)
{
var data = {
@ -81,7 +102,10 @@
if(self.selidx != -1)
self.items[self.selidx].selected =false
self.selidx = data.idx
self.items[self.selidx].selected = true
if(!self.items[self.selidx])
return
self.items[self.selidx].selected = true
if(opts.dropdown == "true")
{
$(self.refs.mlist).hide()
@ -90,7 +114,7 @@
if(self.onlistselect)
self.onlistselect(data)
this.root.observable.trigger('listselect',data)
event.preventDefault()
//event.preventDefault()
}
</script>
</afx-list-view>

View File

@ -1,14 +1,14 @@
<afx-menu >
<ul class={context: opts.context == "true"}>
<li class="afx-corner-fix"></li>
<li ref = "container" each={ item,i in items } class = {afx_submenu:item.child != null, fix_padding:item.icon} no-reorder>
<li ref = "container" each={ data,i in items } class = {afx_submenu:data.child != null, fix_padding:data.icon} no-reorder>
<a href="#" onclick = {parent.onselect}>
<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 }
<i if={data.iconclass} class = {data.iconclass} ></i>
<i if={data.icon} class="icon-style" style = { "background: url("+data.icon+");background-size: 100% 100%;background-repeat: no-repeat;" }></i>
{ data.text }
</a>
<afx-menu if={item.child != null} child={item.child} observable = {parent.root.observable} rootid = {parent.rid}></afx-menu>
<afx-menu if={data.child != null} child={data.child} onmenuselect = {data.onmenuselect} observable = {parent.root.observable} rootid = {parent.rid}></afx-menu>
</li>
<li class="afx-corner-fix"></li>
</ul>
@ -126,8 +126,9 @@
onselect(event)
{
var data = {id:self.rid, data:event.item.item, root:isRoot}
var data = {id:self.rid, root:isRoot, e:event}
this.root.observable.trigger('menuselect',data)
if( this.onmenuselect && !isRoot) this.onmenuselect(data)
event.preventDefault()
$(document).unbind("click",mnhide)
if(opts.context == "true") return

View File

@ -0,0 +1,45 @@
<afx-overlay>
<yield/>
<script>
this.width = opts.width || 200
this.height = opts.height || 400
var self = this;
self.commander = null
this.root.observable = opts.observable || riot.observable()
var id = $(self.root).attr("data-id")
var calibre_size = function()
{
$(self.root)
.css("width", self.width + "px")
.css("height", self.height + "px")
self.root.observable.trigger("resize", {id:id,w:self.width,h:self.height})
}
self.root.set = function(k,v)
{
if(k == "*")
for(var i in v)
self[i] = v[i]
else
self[k] = v
if( k == "width" || k == "height")
calibre_size()
self.update()
}
self.root.get = function(k)
{
return self[k]
}
self.on("mount", function(){
$(self.root)
.css("position", "absolute")
//.css("z-index",1000000)
$(self.root).children().each(function(e){
this.observalbe = self.root.observalbe
})
calibre_size()
self.root.observable.trigger("rendered", self.root)
})
</script>
</afx-overlay>

View File

@ -15,23 +15,31 @@
{text:"NotePad",type:"app", iconclass:"fa fa-commenting"},
{text:"ActivityMonitor",type:"app"},
{text:"DummyApp",type:"app"}
]},
],
onmenuselect: function(d)
{
if(d.e.item.data.type == "app")
window.OS.GUI.launch(d.e.item.data.text)
}
},
{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()}}
this.systray = {
child: [],
onmenuselect: function(d){
if(d.root)
d.e.item.data.awake(d.e)
}
}
var self = this
self.root.attachservice = function(s)
{
s.attach(self.refs.aTray)
self.refs.aTray.root.unshift(s,true)
s.attach(self.refs.aTray)
}
self.root.detachservice = function(s)
{