dialog mechanism

This commit is contained in:
Xuan Sang LE
2017-08-24 01:53:13 +02:00
parent 978dee5f91
commit 8f9dd68213
18 changed files with 381 additions and 146 deletions

View File

@ -1,7 +1,4 @@
self = this
_PM = self.OS.PM
_APP = self.OS.APP
_MAIL = self.OS.courrier
class BaseApplication extends this.OS.GUI.BaseModel
constructor: (name) ->
super name
@ -16,9 +13,11 @@ class BaseApplication extends this.OS.GUI.BaseModel
me.appmenu.set "items", (me.baseMenu() || [])
me.appmenu.set "onmenuselect", (d) ->
me.trigger("menuselect", d)
me.dialog.show() if me.dialog
@on "hide", () ->
me.sysdock.set "selectedApp", null
me.appmenu.set "items", []
me.dialog.hide() if me.dialog
@on "menuselect", (d) ->
switch d.e.item.data.dataid
when "#{me.name}-about" then alert "About " + me.pid + me.name

View File

@ -0,0 +1,85 @@
class BaseDialog extends this.OS.GUI.BaseModel
constructor: (name) ->
super name
@parent = undefined
@modal = false
@handler = undefined
quit: () ->
evt = new _GUI.BaseEvent("exit")
@onexit(evt)
if not evt.prevent
delete @.observable
@parent.dialog = undefined if @parent
($ @scheme).remove() if @scheme
@dialog.quit() if @dialog
meta: () ->
@parent.meta()
show: () ->
@trigger 'focus'
($ @scheme).css "z-index", window._zindex+2
hide: () ->
@trigger 'hide'
BaseDialog.type = 3
this.OS.GUI.BaseDialog = BaseDialog
###
this dialog rende a tag as main content
and a list of buttons, the behaviour of
the button is specified by user. The conf
object is in the follow form
{
tag: <tag_name>,
buttons:[
{
label: 'buton label',
onclick: function(d){...}
}, ...
]
}
###
class BasicDialog extends BaseDialog
constructor: ( name, @conf ) ->
super name
html = "<afx-app-window data-id = 'dia-window' apptitle='#{name}' width='#{@conf.width}' height='#{@conf.height}'>
<afx-hbox>"
html += "<#{@conf.tag} data-id = 'content'></#{@conf.tag}>"
html += "<div data-height = '40' style='padding:5px; text-align:right;'>"
html += "<afx-button data-id = 'bt#{k}' text = '#{v.label}' style='margin-left:5px;'></afx-button>" for k,v of @conf.buttons
html += "</div></afx-hbox></afx-app-window>"
#render the html
_GUI.htmlToScheme html, @, @host
main: () ->
@scheme.set "minimizable", false
me = @
f = (_v) -> () -> _v.onclick me
# bind action to button
( (me.find "bt#{k}").set "onbtclick", f(v) ) for k, v of @conf.buttons
this.OS.GUI.BasicDialog = BasicDialog
class CalendarDialog extends BasicDialog
constructor: () ->
super "CalendarDialog", {
tag: 'afx-calendar-view',
width: 300,
height: 220,
buttons: [
{
label: 'Ok',
onclick: (d) ->
date = (d.find "content").get "selectedDate"
if date
d.handler date if d.handler
d.quit()
else
d.notify "Please select a date"
},
{
label: 'Cancel',
onclick: (d) -> d.quit()
}
]
}
this.OS.register "CalendarDialog", CalendarDialog

View File

@ -1,24 +1,21 @@
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()
@_api = self.OS.API
me = @
@on "exit", () -> me.quit()
@parent = "#desktop"
@host = "#desktop"
@dialog = undefined
render: (p) ->
_GUI.loadScheme p, @, @parent
_GUI.loadScheme p, @, @host
quit: () ->
evt = new _GUI.BaseEvent("exit")
@onexit(evt)
if not evt.prevent
delete @.observable
@dialog.quit() if @dialog
_PM.kill @
init: ->
@ -29,11 +26,23 @@ class BaseModel
trigger: (e, d) -> @observable.trigger e, d
subscribe: (e, f) -> _MAIL.on e, f, @
subscribe: (e, f) -> _courrier.on e, f, @
openDialog: (d, f) ->
if @dialog
@dialog.show()
return
if not _GUI.dialog[d]
@error "Dialog #{d} not found"
return
@dialog = new _GUI.dialog[d]()
@dialog.parent = @
@dialog.handler = f
@dialog.pid = @pid
publish: (t, m) ->
mt = @meta()
_MAIL.trigger t, { id: @pid, name: @name, data: { m: m, icon: mt.icon, iconclass: mt.iconclass } }
_courrier.trigger t, { id: @pid, name: @name, data: { m: m, icon: mt.icon, iconclass: mt.iconclass } }
notify: (m) ->
@publish "notification", m

View File

@ -1,5 +1,3 @@
MAIL = this.OS.courrier
_API = this.OS.API
class BaseService extends this.OS.GUI.BaseModel
constructor: (name) ->
super name
@ -13,7 +11,8 @@ class BaseService extends this.OS.GUI.BaseModel
#implement by user
# event registe, etc
# scheme loader
meta: () ->
@
attach: (h) ->
@holder = h

View File

@ -19,7 +19,8 @@ self.OS or=
_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
register: (name, x) ->
if x.type is 3 then self.OS.GUI.dialog[name] = x else _APP[name] = x
PM:
pidalloc: 0

View File

@ -1,20 +1,22 @@
self.OS.GUI =
dialog: new Object()
init: () ->
query =
path: 'VFS/get'
data: "#{_GUI.tagPath}/tags.json"
self.OS.API.request query, ()->
htmlToScheme: (html, app, parent) ->
scheme = $.parseHTML html
($ parent).append scheme
riot.mount ($ scheme), { observable: app.observable }
app.scheme = scheme[0]
app.main()
app.show()
loadScheme: (path, app, parent) ->
_API.get path,
(x) ->
return null unless x
scheme = $.parseHTML x
($ parent).append scheme
riot.mount ($ scheme), { observable: app.observable }
app.scheme = scheme[0]
app.main()
app.show()
_GUI.htmlToScheme x, app, parent
, (f) ->
_courrier.trigger "fail",
{id: 0, data: {

View File

@ -2,8 +2,8 @@
<div class = "afx-window-wrapper">
<ul class= "afx-window-top" >
<li class = "afx-window-close" onclick = {close}></li>
<li class = "afx-window-minimize" onclick = {minimize}></li>
<li class = "afx-window-maximize" onclick={maximize}></li>
<li if = {minimizable == true} class = "afx-window-minimize" onclick = {minimize}></li>
<li if = {maximizable == true} class = "afx-window-maximize" onclick={maximize}></li>
<li ref = "dragger" class = "afx-window-title">{ apptitle }</li>
</ul>
<div class = "afx-clear"></div>
@ -15,6 +15,8 @@
<script>
this.apptitle = opts.apptitle || ""
this.minimizable = eval(opts.minimizable) || true
this.maximizable = eval(opts.maximizable) || true
var self = this
var offset = {top:0,left:0}
var desktop_pos = $("#desktop").offset()
@ -24,7 +26,7 @@
var width = opts.width || 400
var height = opts.height || 300
this.root.observable = opts.observable || riot.observable()
if(!window._zidex) window._zidex = 10
if(!window._zindex) window._zindex = 10
this.shown = false
self.root.set = function(k,v)
{
@ -49,15 +51,15 @@
}
this.on('mount', function() {
var left,top
left = 20 + Math.floor(Math.random() * width)
top = 20 + Math.floor(Math.random() * height)
left = 20 + Math.floor(Math.random() * ($("#desktop").width() - width))
top = 20 + Math.floor(Math.random() * ($("#desktop").height() - height))
$(self.refs.window)
.css("position",'absolute')
.css("left",left + "px")
.css("top",top + "px")
.css("width",width + "px")
.css("height", height + "px")
.css("z-index",window._zidex++)
.css("z-index",window._zindex++)
$(self.refs.window).on("mousedown", function(e){
if(self.shown == false)
self.root.observable.trigger("focus")
@ -78,10 +80,10 @@
})
self.root.observable.on("focus",function(){
window._zidex++
window._zindex++
$(self.refs.window)
.show()
.css("z-index",window._zidex)
.css("z-index",window._zindex)
.removeClass("unactive")
self.shown = true
@ -179,6 +181,7 @@
var toggle_window = function()
{
if(!self.maximizable) return;
if(isMaxi == false)
{
history = {

View File

@ -1,43 +1,78 @@
<afx-calendar-view>
<div>{text}</div>
<afx-grid-view style = "height:100%;" ref = "grid" header = {header} observable = {root.observable}> </afx-grid-view>
<div><i class ="prevmonth" onclick={prevmonth}></i>{text}<i onclick={nextmonth} class="nextmonth"></i></div>
<afx-grid-view data-id ={"grid_" + rid} style = "height:100%;" ref = "grid" header = {header} observable = {root.observable}> </afx-grid-view>
<script >
this.header = [{value:"S"},{value:"M"},{value:"T"},{value:"W"},{value:"T"},{value:"F"},{value:"S"}]
this.header = [{value:"Sun"},{value:"Mon"},{value:"Tue"},{value:"Wed"},{value:"Thu"},{value:"Fri"},{value:"Sat"}]
this.root.observable = opts.observable
this.on("mount", function (e) {
calendar(null)
self.refs.grid.root.set("rows",self.rows)
})
this.on("updated", function(e){
if (self.refs.grid.root.observable != self.root.observable)
{
console.log("reset observable")
}
})
var self = this
this.day = 0
this.month = 0
this.year = 0
this.ondayselect = opts.ondayselect
this.rid = $(self.root).attr("data-id") || Math.floor(Math.random() * 100000) + 1
this.selectedDate = undefined
self.root.get = function(k)
{
return self[k]
}
this.on("mount", function (e) {
self.refs.grid.root.observable = self.root.observable
calendar(null)
self.root.observable.on("gridcellselect", function(d){
if(d.id != "grid_" + self.rid) return
if(d.data.value == "") return
var data = {id:self.rid, data:new Date(self.year, self.month,d.data.value)};
if(self.ondayselect)
self.ondayselect(data)
self.selectedDate = data.data
self.root.observable.trigger("dayselect",data)
})
})
prevmonth()
{
self.selectedDate = undefined
this.month--
if(this.month < 0)
{
this.month = 11
this.year--
}
calendar(new Date(this.year, this.month,1))
}
nextmonth()
{
self.selectedDate = undefined
this.month++
if(this.month > 11)
{
this.month = 0
this.year++
}
calendar(new Date(this.year, this.month,1))
}
var calendar = function (date) {
if (date === null)
date = new Date()
day = date.getDate()
month = date.getMonth()
year = date.getFullYear()
self.day = date.getDate()
self.month = date.getMonth()
self.year = date.getFullYear()
var now ={ d:(new Date()).getDate(), m:(new Date()).getMonth(), y:(new Date()).getFullYear()}
months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
this_month = new Date(year, month, 1)
next_month = new Date(year, month + 1, 1)
this_month = new Date(self.year, self.month, 1)
next_month = new Date(self.year, self.month + 1, 1)
// Find out when this month starts and ends.
first_week_day = this_month.getDay()
days_in_this_month = Math.round((next_month.getTime() - this_month.getTime()) / (1000 * 60 * 60 * 24))
self.text = months[month] + ' ' + year
self.rows = []
self.text = months[self.month] + ' ' + self.year
var rows = []
var row = []
console.log(days_in_this_month)
// Fill the first week of the month with the appropriate number of blanks.
for (week_day = 0; week_day < first_week_day; week_day++)
row.push({value:""})
@ -47,21 +82,23 @@
week_day %= 7
if (week_day == 0)
{
self.rows.push(row)
rows.push(row)
row =[]
}
// Do something different for the current day.
//if (day == day_counter)
// calendar_html += '<td style="text-align: center;"><b>' + day_counter + '</b></td>';
//else
// calendar_html += '<td style="background-color:9999cc; color:000000; text-align: center;"> ' + day_counter + ' </td>';
row.push({value:day_counter})
if (now.d == day_counter && self.month == now.m && self.year == now.y)
row.push({value:day_counter, selected:true})
else
row.push({value:day_counter})
week_day++;
}
for(var i = 0; i <= 7 - row.length;i++)
row.push({value:""})
self.rows.push(row)
rows.push(row)
self.refs.grid.root.set("rows",rows)
}
</script>
</afx-calendar-view>

View File

@ -2,7 +2,7 @@
<afx-grid-row ref="gridhead" rootid = {rid} observable = {root.observable} header="true" class = {grid_row_header:header} if = {header} cols = {header}> </afx-grid-row>
<div ref = "scroller" style="width:100%; overflow:auto;">
<div ref = "container">
<afx-grid-row each={ child, i in rows } class = {selected: child.selected} rootid = {parent.rid} observable = {parent.root.observable} cols = {child} onclick = {parent._select}></afx-grid-row>
<afx-grid-row each={ child, i in rows } class = {selected: child.selected} rootid = {parent.rid} observable = {parent.root.observable} index = {i} cols = {child} onclick = {parent._select} head = {parent.refs.gridhead} ></afx-grid-row>
</div>
</div>
<script>
@ -28,11 +28,12 @@
if(self.header)
{
$(self.refs.scroller).css("height",
$(self.root).height() - $(self.refs.gridhead.root).height()
$(self.root).height() - $(self.refs.gridhead.root).children().first().height()
+ "px")
}
else
$(self.refs.scroller).css("height","100%")
$(self.refs.scroller).css("height",
$(self.root).height() + "px")
}
self.root.get = function(k)
@ -42,24 +43,17 @@
return self[k]
}
if(opts.observable)
this.root.observable = opts.observable
else
{
this.root.observable = riot.observable()
}
this.root.observable = opts.observable || riot.observable()
this.on("mount", function(){
$(self.refs.container)
.css("display","flex")
.css("flex-direction","column")
.css("display","table")
//.css("flex-direction","column")
.css("width","100%")
self.calibrate_size()
this.root.observable.on("resize",function(){
self.calibrate_size()
if(self.refs.gridhead)
self.refs.gridhead.calibrate_size()
})
})
this.on("updated",function(){
@ -68,8 +62,6 @@
if(self.nrow == self.rows.length) return
self.nrow = self.rows.length
self.calibrate_size()
if(self.refs.gridhead)
self.refs.gridhead.calibrate_size()
})
_select(event)
{
@ -84,14 +76,15 @@
self.rows[self.selidx].selected = true
this.root.observable.trigger('gridselect',data)
event.preventUpdate = true
self.update()
event.preventDefault()
self.update()
//event.preventDefault()
}
</script>
</afx-grid-view>
<afx-grid-row>
<div style = "flex-grow:1;" each = { child,i in cols } class = {string:typeof child.value == "string", number: typeof child.value == "number"} >
<div style = {!header? "display: table-cell;" :""} onclick = {parent._cell_select} each = { child,i in cols } class = {string:typeof child.value == "string", number: typeof child.value == "number", cellselected: parent._auto_cell_select(child,i)} >
<i if={child.iconclass} class = {child.iconclass} ></i>
<i if={child.icon} class="icon-style" style = { "background: url("+child.icon+");background-size: 100% 100%;background-repeat: no-repeat;" }></i>
{child.value}
@ -100,58 +93,112 @@
this.cols = opts.cols || []
var self = this
this.rid = opts.rootid
this.observable = opts.observable
this.index = opts.index
this.header = opts.header||false
this.calibrate_size = function()
this.head = opts.head
this.selidx = -1;
self.observable = opts.observable
this.colssize = []
var update_header_size = function()
{
if(!self.cols || self.cols.length == 0 || !self.observable) return
if(!self.cols || self.cols.length == 0) return
var totalw = $(self.root).parent().width()
if(totalw == 0) return
var ocw = 0
var nauto = 0
var dist = []
self.colssize = []
$.each(self.cols, function(i,e){
if(e.width)
{
dist.push(e.width)
self.colssize.push(e.width)
ocw += e.width
}
else
{
dist.push(-1)
self.colssize.push(-1)
nauto++
}
})
if(nauto > 0)
{
var cellw = (totalw - ocw)/ nauto
$.each(dist,function(i,e){
if(e == -1) dist[i] = cellw
})
var cellw = parseInt((totalw - ocw)/ nauto)
$.each(self.colssize,function(i,e){if(e == -1) self.colssize[i] = cellw})
}
self.observable.trigger("cellresize",{id:self.rid,data:dist})
calibrate_size()
}
self.observable.on("cellresize",function(d){
if(d.id && d.id == self.rid)
{
var i = 0
$(self.root)
.children()
.each(function(){
$(this).css("width", d.data[i]+"px")
i++
})
}
})
this.on("mount", function(){
var calibrate_size = function()
{
var i = 0
$(self.root)
.css("display","flex")
.css("flex-direction","row")
.css("width","100%")
.children()
.each(function(){
$(this).css("width", self.colssize[i]+"px")
i++
})
}
this.on("updated", function(){
if(self.header)
self.calibrate_size()
update_header_size()
else if(self.head && self.index == 0)
{
self.colssize = self.head.colssize
calibrate_size()
}
})
this.on("mount", function(){
if (self.header)
{
$(self.root)
.css("display", "flex")
.css("flex-direction", "row")
update_header_size()
}
else
{
$(self.root)
.css("display","table-row")
//.css("flex-direction","row")
.css("width","100%")
if(self.head && self.index == 0)
{
self.colssize = self.head.colssize
calibrate_size()
}
}
self.observable.on("gridcellselect", function(data){
if(data.id != self.rid || self.selidx == -1) return;
if(data.row != self.index)
{
self.cols[self.selidx].selected = false
self.selidx = -1
}
})
})
_cell_select(event)
{
if(self.header) return;
if(self.selidx != -1)
{
self.cols[self.selidx].selected = false
self.selidx = -1
}
self.cols[event.item.i].selected = true
}
_auto_cell_select(child,i)
{
if(!child.selected || self.header) return false;
if(self.selidx == i) return true;
var data = {
id:self.rid,
data:child,
col:i,
row:self.index}
self.selidx = i
self.observable.trigger("gridcellselect",data)
return true;
}
</script>
</afx-grid-row>